1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2008-2021 Free Software Foundation, Inc.
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 3 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General
15 Public License along with this library; If not, see
16 <http://www.gnu.org/licenses/>. */
17
18 /* This is an `m-server' - a universal framework for multi-process TCP
19 servers. An `m-' stands for `mail-', or `multi-' or maybe `meta-',
20 I don't remember what. */
21
22 #ifdef HAVE_CONFIG_H
23 # include <config.h>
24 #endif
25 #include <sys/types.h>
26 #include <sys/wait.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <unistd.h>
31 #include <syslog.h>
32 #include <netdb.h>
33 #include <sys/socket.h>
34 #include <sys/un.h>
35 #include <sys/stat.h>
36 #include <limits.h>
37 #include <mailutils/cctype.h>
38 #include <mailutils/server.h>
39 #include <mailutils/error.h>
40 #include <mailutils/errno.h>
41 #include <mailutils/cfg.h>
42 #include <mailutils/nls.h>
43 #include <mailutils/daemon.h>
44 #include <mailutils/acl.h>
45 #include <mailutils/sockaddr.h>
46 #include <mailutils/url.h>
47 #include <mailutils/util.h>
48
49 typedef RETSIGTYPE (*mu_sig_handler_t) (int);
50
51 static mu_sig_handler_t
set_signal(int sig,mu_sig_handler_t handler)52 set_signal (int sig, mu_sig_handler_t handler)
53 {
54 #ifdef HAVE_SIGACTION
55 {
56 struct sigaction act, oldact;
57 act.sa_handler = handler;
58 sigemptyset (&act.sa_mask);
59 act.sa_flags = 0;
60 sigaction (sig, &act, &oldact);
61 return oldact.sa_handler;
62 }
63 #else
64 return signal (sig, handler);
65 #endif
66 }
67
68 #ifndef NSIG
69 # define NSIG 64
70 #endif
71
72 struct _mu_m_server
73 {
74 char *ident; /* Server identifier, for logging purposes.*/
75 int deftype; /* Default server type: MU_IP_TCP/MU_IP_UDP */
76 mu_server_t server; /* The server object. */
77 mu_list_t srvlist; /* A list of configured mu_ip_server_t
78 objects. It is cleared after the objects
79 are opened and attached to the server. */
80 mu_m_server_preflight_fp preflight; /* Pre-flight check function */
81 mu_m_server_handler_fp conn; /* Connection handler function. */
82 mu_m_server_handler_fp prefork;/* Pre-fork function. */
83 void *data; /* User-supplied data for conn and prefork. */
84 size_t app_data_size;
85
86 int mode; /* Server mode: should be removed. */
87
88 int foreground; /* Should the server remain in foregorund? */
89 size_t max_children; /* Maximum number of sub-processes to run. */
90 size_t num_children; /* Current number of running sub-processes. */
91 pid_t *child_pid;
92 char *pidfile; /* Name of a PID-file. */
93 struct mu_sockaddr_hints hints; /* Default address hints. */
94 time_t timeout; /* Default idle timeout. */
95 mu_acl_t acl; /* Global access control list. */
96
97 sigset_t sigmask; /* A set of signals to handle by the
98 m-server. */
99 mu_sig_handler_t sigtab[NSIG]; /* Keeps old signal handlers. */
100 const char *(*strexit) (int); /* Convert integer exit code to textual
101 description. */
102 };
103
104
105 static int need_cleanup = 0;
106 static int stop = 0; /* FIXME: Must be per-m-server */
107 static mu_list_t m_server_list;
108
109 #define UNUSED_PID ((pid_t)-1)
110
111 static void
alloc_children(mu_m_server_t srv)112 alloc_children (mu_m_server_t srv)
113 {
114 int i;
115 size_t size = srv->max_children * sizeof (srv->child_pid[0]);
116
117 srv->child_pid = malloc (size);
118
119 if (!srv->child_pid)
120 {
121 mu_error ("%s", mu_strerror (ENOMEM));
122 abort ();
123 }
124
125 for (i = 0; i < srv->max_children; i++)
126 srv->child_pid[i] = UNUSED_PID;
127 }
128
129 static void
register_child(mu_m_server_t msrv,pid_t pid)130 register_child (mu_m_server_t msrv, pid_t pid)
131 {
132 int i;
133
134 msrv->num_children++;
135 for (i = 0; i < msrv->max_children; i++)
136 if (msrv->child_pid[i] == UNUSED_PID)
137 {
138 msrv->child_pid[i] = pid;
139 return;
140 }
141 mu_error ("%s:%d: cannot find free PID slot (internal error?)",
142 __FILE__, __LINE__);
143 }
144
145 static int
unregister_child(mu_m_server_t msrv,pid_t pid)146 unregister_child (mu_m_server_t msrv, pid_t pid)
147 {
148 int i;
149
150 msrv->num_children--;
151 for (i = 0; i < msrv->max_children; i++)
152 if (msrv->child_pid[i] == pid)
153 {
154 msrv->child_pid[i] = UNUSED_PID;
155 return 0;
156 }
157 return 1;
158 }
159
160 static void
terminate_children(mu_m_server_t msrv)161 terminate_children (mu_m_server_t msrv)
162 {
163 if (msrv->child_pid)
164 {
165 int i;
166
167 for (i = 0; i < msrv->max_children; i++)
168 if (msrv->child_pid[i] != UNUSED_PID)
169 kill (msrv->child_pid[i], SIGTERM);
170 }
171 }
172
173 void
mu_m_server_stop(int code)174 mu_m_server_stop (int code)
175 {
176 stop = code;
177 }
178
179 struct exit_data
180 {
181 pid_t pid;
182 int status;
183 };
184
185 static int
m_server_cleanup(void * item,void * data)186 m_server_cleanup (void *item, void *data)
187 {
188 mu_m_server_t msrv = item;
189 struct exit_data *datp = data;
190
191 if (unregister_child (msrv, datp->pid) == 0)
192 {
193 if (WIFEXITED (datp->status))
194 {
195 int prio = MU_DIAG_INFO;
196 int code = WEXITSTATUS (datp->status);
197 if (code == 0)
198 prio = MU_DIAG_DEBUG;
199 if (msrv->strexit)
200 mu_diag_output (prio,
201 _("process %lu finished with code %d (%s)"),
202 (unsigned long) datp->pid,
203 code,
204 msrv->strexit (code));
205 else
206 mu_diag_output (prio,
207 _("process %lu finished with code %d"),
208 (unsigned long) datp->pid,
209 code);
210 }
211 else if (WIFSIGNALED (datp->status))
212 mu_diag_output (MU_DIAG_ERR, "process %lu terminated on signal %d",
213 (unsigned long) datp->pid,
214 WTERMSIG (datp->status));
215 else
216 mu_diag_output (MU_DIAG_ERR,
217 "process %lu terminated (cause unknown)",
218 (unsigned long) datp->pid);
219 return MU_ERR_USER0;
220 }
221 return 0;
222 }
223
224 static int
mu_m_server_idle(void * server_data MU_ARG_UNUSED)225 mu_m_server_idle (void *server_data MU_ARG_UNUSED)
226 {
227 if (need_cleanup)
228 {
229 struct exit_data ex;
230
231 need_cleanup = 0;
232 while ( (ex.pid = waitpid (-1, &ex.status, WNOHANG)) > 0)
233 /* Iterate over all m-servers and notify them about the fact. */
234 mu_list_foreach (m_server_list, m_server_cleanup, &ex);
235 }
236 return stop;
237 }
238
239 static RETSIGTYPE
m_srv_signal(int signo)240 m_srv_signal (int signo)
241 {
242 switch (signo)
243 {
244 case SIGCHLD:
245 need_cleanup = 1;
246 break;
247
248 default:
249 stop = 1;
250 break;
251 }
252 #ifndef HAVE_SIGACTION
253 signal (signo, m_srv_sigchld);
254 #endif
255 }
256
257 void
mu_m_server_create(mu_m_server_t * psrv,const char * ident)258 mu_m_server_create (mu_m_server_t *psrv, const char *ident)
259 {
260 mu_m_server_t srv = calloc (1, sizeof *srv);
261 if (!srv)
262 {
263 mu_error ("%s", mu_strerror (ENOMEM));
264 exit (1);
265 }
266 if (ident)
267 {
268 srv->ident = strdup (ident);
269 if (!srv->ident)
270 {
271 mu_error ("%s", mu_strerror (ENOMEM));
272 exit (1);
273 }
274 }
275 srv->deftype = MU_IP_TCP;
276 MU_ASSERT (mu_server_create (&srv->server));
277 mu_server_set_idle (srv->server, mu_m_server_idle);
278 sigemptyset (&srv->sigmask);
279 sigaddset (&srv->sigmask, SIGCHLD);
280 sigaddset (&srv->sigmask, SIGINT);
281 sigaddset (&srv->sigmask, SIGTERM);
282 sigaddset (&srv->sigmask, SIGQUIT);
283 sigaddset (&srv->sigmask, SIGHUP);
284 *psrv = srv;
285 if (!m_server_list)
286 mu_list_create (&m_server_list);
287 mu_list_append (m_server_list, srv);
288 }
289
290 void
mu_m_server_set_type(mu_m_server_t srv,int type)291 mu_m_server_set_type (mu_m_server_t srv, int type)
292 {
293 srv->deftype = type;
294 }
295
296 void
mu_m_server_get_type(mu_m_server_t srv,int * type)297 mu_m_server_get_type (mu_m_server_t srv, int *type)
298 {
299 *type = srv->deftype;
300 }
301
302 void
mu_m_server_set_sigset(mu_m_server_t srv,sigset_t * sigset)303 mu_m_server_set_sigset (mu_m_server_t srv, sigset_t *sigset)
304 {
305 srv->sigmask = *sigset;
306 sigaddset (&srv->sigmask, SIGCHLD);
307 }
308
309 void
mu_m_server_get_sigset(mu_m_server_t srv,sigset_t * sigset)310 mu_m_server_get_sigset (mu_m_server_t srv, sigset_t *sigset)
311 {
312 *sigset = srv->sigmask;
313 }
314
315 void
mu_m_server_set_mode(mu_m_server_t srv,int mode)316 mu_m_server_set_mode (mu_m_server_t srv, int mode)
317 {
318 srv->mode = mode;
319 }
320
321 void
mu_m_server_set_conn(mu_m_server_t srv,mu_m_server_handler_fp conn)322 mu_m_server_set_conn (mu_m_server_t srv, mu_m_server_handler_fp conn)
323 {
324 srv->conn = conn;
325 }
326
327 void
mu_m_server_set_prefork(mu_m_server_t srv,mu_m_server_handler_fp fun)328 mu_m_server_set_prefork (mu_m_server_t srv, mu_m_server_handler_fp fun)
329 {
330 srv->prefork = fun;
331 }
332
333 void
mu_m_server_set_data(mu_m_server_t srv,void * data)334 mu_m_server_set_data (mu_m_server_t srv, void *data)
335 {
336 srv->data = data;
337 }
338
339 void
mu_m_server_set_max_children(mu_m_server_t srv,size_t num)340 mu_m_server_set_max_children (mu_m_server_t srv, size_t num)
341 {
342 srv->max_children = num;
343 }
344
345 int
mu_m_server_set_pidfile(mu_m_server_t srv,const char * pidfile)346 mu_m_server_set_pidfile (mu_m_server_t srv, const char *pidfile)
347 {
348 char *p = strdup (pidfile);
349 if (!p)
350 return errno;
351 free (srv->pidfile);
352 srv->pidfile = p;
353 return 0;
354 }
355
356 int
mu_m_server_set_foreground(mu_m_server_t srv,int enable)357 mu_m_server_set_foreground (mu_m_server_t srv, int enable)
358 {
359 srv->foreground = enable;
360 return 0;
361 }
362
363 void
mu_m_server_set_strexit(mu_m_server_t srv,const char * (* fun)(int))364 mu_m_server_set_strexit (mu_m_server_t srv, const char *(*fun) (int))
365 {
366 srv->strexit = fun;
367 }
368
369 void
mu_m_server_set_preflight(mu_m_server_t srv,mu_m_server_preflight_fp fun)370 mu_m_server_set_preflight (mu_m_server_t srv, mu_m_server_preflight_fp fun)
371 {
372 srv->preflight = fun;
373 }
374
375 int
mu_m_server_get_srvlist(mu_m_server_t srv,mu_list_t * plist)376 mu_m_server_get_srvlist (mu_m_server_t srv, mu_list_t *plist)
377 {
378 *plist = srv->srvlist;
379 return 0;
380 }
381
382 const char *
mu_m_server_pidfile(mu_m_server_t srv)383 mu_m_server_pidfile (mu_m_server_t srv)
384 {
385 return srv->pidfile;
386 }
387
388 void
mu_m_server_set_hints(mu_m_server_t srv,struct mu_sockaddr_hints * hints)389 mu_m_server_set_hints (mu_m_server_t srv, struct mu_sockaddr_hints *hints)
390 {
391 if (!hints)
392 memset (&srv->hints, 0, sizeof (srv->hints));
393 else
394 memcpy (&srv->hints, hints, sizeof (srv->hints));
395 }
396
397 int
mu_m_server_get_hints(mu_m_server_t srv,struct mu_sockaddr_hints * hints)398 mu_m_server_get_hints (mu_m_server_t srv, struct mu_sockaddr_hints *hints)
399 {
400 if (!hints)
401 return EINVAL;
402 memcpy (hints, &srv->hints, sizeof (*hints));
403 return 0;
404 }
405
406
407 void
mu_m_server_set_default_port(mu_m_server_t srv,int num)408 mu_m_server_set_default_port (mu_m_server_t srv, int num)
409 {
410 srv->hints.port = num;
411 }
412
413 void
mu_m_server_set_timeout(mu_m_server_t srv,time_t t)414 mu_m_server_set_timeout (mu_m_server_t srv, time_t t)
415 {
416 srv->timeout = t;
417 }
418
419 int
mu_m_server_mode(mu_m_server_t srv)420 mu_m_server_mode (mu_m_server_t srv)
421 {
422 return srv->mode;
423 }
424
425 time_t
mu_m_server_timeout(mu_m_server_t srv)426 mu_m_server_timeout (mu_m_server_t srv)
427 {
428 return srv->timeout;
429 }
430
431 int
mu_m_server_foreground(mu_m_server_t srv)432 mu_m_server_foreground (mu_m_server_t srv)
433 {
434 return srv->foreground;
435 }
436
437 void
mu_m_server_set_app_data_size(mu_m_server_t srv,size_t size)438 mu_m_server_set_app_data_size (mu_m_server_t srv, size_t size)
439 {
440 srv->app_data_size = size;
441 }
442
443 int
mu_m_server_set_config_size(mu_m_server_t srv,size_t size)444 mu_m_server_set_config_size (mu_m_server_t srv, size_t size)
445 {
446 if (size < sizeof (struct mu_srv_config))
447 return EINVAL;
448 srv->app_data_size = size - sizeof (struct mu_srv_config);
449 return 0;
450 }
451
452 void
mu_srv_config_free(void * data)453 mu_srv_config_free (void *data)
454 {
455 struct mu_srv_config *pconf = data;
456 /* FIXME */
457 free (pconf);
458 }
459
460 static int m_srv_conn (int fd, struct sockaddr *sa, int salen,
461 void *server_data, void *call_data,
462 mu_ip_server_t srv);
463
464 struct mu_srv_config *
mu_m_server_listen(mu_m_server_t msrv,struct mu_sockaddr * s,int type)465 mu_m_server_listen (mu_m_server_t msrv, struct mu_sockaddr *s, int type)
466 {
467 mu_ip_server_t tcpsrv;
468 struct mu_srv_config *pconf;
469
470 MU_ASSERT (mu_ip_server_create (&tcpsrv, s, type)); /* FIXME: type */
471 MU_ASSERT (mu_ip_server_set_conn (tcpsrv, m_srv_conn));
472 pconf = calloc (1, sizeof (*pconf) + msrv->app_data_size);
473 if (!pconf)
474 {
475 mu_error ("%s", mu_strerror (ENOMEM));
476 exit (1);
477 }
478 pconf->msrv = msrv;
479 pconf->tcpsrv = tcpsrv;
480 pconf->single_process = 0;
481 pconf->timeout = msrv->timeout;
482 MU_ASSERT (mu_ip_server_set_data (tcpsrv, pconf, mu_srv_config_free));
483 if (!msrv->srvlist)
484 MU_ASSERT (mu_list_create (&msrv->srvlist));
485 MU_ASSERT (mu_list_append (msrv->srvlist, tcpsrv));
486 return pconf;
487 }
488
489 void
mu_m_server_configured_count(mu_m_server_t msrv,size_t * count)490 mu_m_server_configured_count (mu_m_server_t msrv, size_t *count)
491 {
492 mu_list_count (msrv->srvlist, count);
493 }
494
495 void
mu_m_server_begin(mu_m_server_t msrv)496 mu_m_server_begin (mu_m_server_t msrv)
497 {
498 int i, rc;
499 size_t count = 0;
500
501 if (!msrv->child_pid)
502 alloc_children (msrv);
503
504 mu_list_count (msrv->srvlist, &count);
505 if (count == 0)
506 {
507 struct mu_sockaddr *ta;
508
509 msrv->hints.flags = MU_AH_PASSIVE;
510 rc = mu_sockaddr_from_node (&ta, NULL, NULL, &msrv->hints);
511 if (rc == 0)
512 while (ta)
513 {
514 struct mu_sockaddr *next = ta->next;
515 ta->next = ta->prev = NULL;
516 mu_m_server_listen (msrv, ta, msrv->deftype);
517 ta = next;
518 }
519 }
520
521 if (!msrv->foreground)
522 {
523 /* Become a daemon. Take care to close inherited fds and to hold
524 first three one, in, out, err */
525 if ((rc = mu_daemon ()) != 0)
526 {
527 mu_error (_("failed to become a daemon: %s"), mu_strerror (rc));
528 exit (EXIT_FAILURE);
529 }
530 mu_onexit_reset ();
531 }
532
533 if (msrv->pidfile)
534 switch (rc = mu_daemon_create_pidfile (msrv->pidfile))
535 {
536 case 0:
537 break;
538
539 case EINVAL:
540 mu_error (_("%s: invalid name for a pidfile"), msrv->pidfile);
541 break;
542
543 default:
544 mu_error (_("cannot create pidfile `%s': %s"), msrv->pidfile,
545 mu_strerror (rc));
546 }
547
548 for (i = 0; i < NSIG; i++)
549 if (sigismember (&msrv->sigmask, i))
550 msrv->sigtab[i] = set_signal (i, m_srv_signal);
551 }
552
553 void
mu_m_server_restore_signals(mu_m_server_t msrv)554 mu_m_server_restore_signals (mu_m_server_t msrv)
555 {
556 int i;
557
558 for (i = 0; i < NSIG; i++)
559 if (sigismember (&msrv->sigmask, i))
560 set_signal (i, msrv->sigtab[i]);
561 }
562
563 void
mu_m_server_end(mu_m_server_t msrv)564 mu_m_server_end (mu_m_server_t msrv)
565 {
566 mu_m_server_restore_signals (msrv);
567 }
568
569 void
mu_m_server_destroy(mu_m_server_t * pmsrv)570 mu_m_server_destroy (mu_m_server_t *pmsrv)
571 {
572 mu_m_server_t msrv = *pmsrv;
573 mu_list_remove (m_server_list, msrv);
574 mu_list_destroy (&msrv->srvlist);
575 mu_server_destroy (&msrv->server);
576 free (msrv->child_pid);
577 /* FIXME: Send processes the TERM signal here?*/
578 free (msrv->ident);
579 free (msrv);
580 *pmsrv = NULL;
581 }
582
583 static int
tcp_conn_handler(int fd,void * conn_data,void * server_data)584 tcp_conn_handler (int fd, void *conn_data, void *server_data)
585 {
586 mu_ip_server_t tcpsrv = (mu_ip_server_t) conn_data;
587 int rc = mu_ip_server_accept (tcpsrv, server_data);
588 if (rc && rc != EINTR)
589 {
590 mu_ip_server_shutdown (tcpsrv);
591 return MU_SERVER_CLOSE_CONN;
592 }
593 return stop ? MU_SERVER_SHUTDOWN : MU_SERVER_SUCCESS;
594 }
595
596 static void
tcp_conn_free(void * conn_data,void * server_data)597 tcp_conn_free (void *conn_data, void *server_data)
598 {
599 mu_ip_server_t tcpsrv = (mu_ip_server_t) conn_data;
600 mu_ip_server_destroy (&tcpsrv);
601 }
602
603 static int
open_connection(mu_ip_server_t tcpsrv,mu_m_server_t msrv)604 open_connection (mu_ip_server_t tcpsrv, mu_m_server_t msrv)
605 {
606 int rc = mu_ip_server_open (tcpsrv);
607 if (rc)
608 {
609 mu_error (_("cannot open connection on %s: %s"),
610 mu_ip_server_addrstr (tcpsrv), mu_strerror (rc));
611 return rc;
612 }
613
614 rc = mu_server_add_connection (msrv->server,
615 mu_ip_server_get_fd (tcpsrv),
616 tcpsrv,
617 tcp_conn_handler, tcp_conn_free);
618 if (rc)
619 {
620 mu_error (_("cannot add connection %s: %s"),
621 mu_ip_server_addrstr (tcpsrv), mu_strerror (rc));
622 mu_ip_server_shutdown (tcpsrv);
623 }
624 return rc;
625 }
626
627 int
mu_m_server_run(mu_m_server_t msrv)628 mu_m_server_run (mu_m_server_t msrv)
629 {
630 int rc;
631 size_t count;
632 mode_t saved_umask;
633 mu_iterator_t itr;
634
635 saved_umask = umask (0117);
636 mu_list_get_iterator (msrv->srvlist, &itr);
637 for (mu_iterator_first (itr); !mu_iterator_is_done (itr); mu_iterator_next (itr))
638 {
639 mu_ip_server_t tcpsrv;
640 mu_iterator_current (itr, (void**) &tcpsrv);
641 if (open_connection (tcpsrv, msrv))
642 {
643 mu_iterator_ctl (itr, mu_itrctl_delete_nd, NULL);
644 mu_ip_server_destroy (&tcpsrv);
645 }
646 }
647 umask (saved_umask);
648 mu_iterator_destroy (&itr);
649
650 MU_ASSERT (mu_server_count (msrv->server, &count));
651 if (count == 0)
652 {
653 mu_error (_("no servers configured: exiting"));
654 exit (1);
655 }
656 if (msrv->preflight && msrv->preflight (msrv))
657 {
658 mu_error (_("%s: preflight check failed"), msrv->ident);
659 return MU_ERR_FAILURE;
660 }
661
662 if (msrv->ident)
663 mu_diag_output (MU_DIAG_INFO, _("%s started"), msrv->ident);
664 rc = mu_server_run (msrv->server);
665 terminate_children (msrv);
666 if (msrv->ident)
667 mu_diag_output (MU_DIAG_INFO, _("%s terminated"), msrv->ident);
668 return rc;
669 }
670
671 int
mu_m_server_check_acl(mu_m_server_t msrv,struct sockaddr * s,int salen)672 mu_m_server_check_acl (mu_m_server_t msrv, struct sockaddr *s, int salen)
673 {
674 if (msrv->acl)
675 {
676 mu_acl_result_t res;
677 int rc;
678
679 rc = mu_acl_check_sockaddr (msrv->acl, s, salen, &res);
680 if (rc)
681 {
682 char *p = mu_sys_sockaddr_to_astr (s, salen);
683 mu_error (_("access from %s blocked: cannot check ACLs: %s"),
684 p, mu_strerror (rc));
685 free (p);
686 return 1;
687 }
688 switch (res)
689 {
690 case mu_acl_result_undefined:
691 {
692 char *p = mu_sys_sockaddr_to_astr (s, salen);
693 mu_diag_output (MU_DIAG_INFO,
694 _("%s: undefined ACL result; access allowed"),
695 p);
696 free (p);
697 }
698 break;
699
700 case mu_acl_result_accept:
701 break;
702
703 case mu_acl_result_deny:
704 {
705 char *p = mu_sys_sockaddr_to_astr (s, salen);
706 mu_error (_("access from %s blocked"), p);
707 free (p);
708 return 1;
709 }
710 }
711 }
712 return 0;
713 }
714
715 int
m_srv_conn(int fd,struct sockaddr * sa,int salen,void * server_data,void * call_data,mu_ip_server_t srv)716 m_srv_conn (int fd, struct sockaddr *sa, int salen,
717 void *server_data, void *call_data,
718 mu_ip_server_t srv)
719 {
720 int status;
721 struct mu_srv_config *pconf = server_data;
722
723 if (mu_m_server_check_acl (pconf->msrv, sa, salen))
724 return 0;
725
726 if (!pconf->single_process)
727 {
728 pid_t pid;
729
730 if (mu_m_server_idle (server_data))
731 return MU_SERVER_SHUTDOWN;
732 if (pconf->msrv->max_children
733 && pconf->msrv->num_children >= pconf->msrv->max_children)
734 {
735 mu_diag_output (MU_DIAG_ERROR, _("too many children (%lu)"),
736 (unsigned long) pconf->msrv->num_children);
737 pause ();
738 return 0;
739 }
740 if (pconf->msrv->prefork
741 && pconf->msrv->prefork (fd, sa, salen, pconf, pconf->msrv->data))
742 return 0;
743
744 pid = fork ();
745 if (pid == -1)
746 mu_diag_output (MU_DIAG_ERROR, "fork: %s", strerror (errno));
747 else if (pid == 0) /* Child. */
748 {
749 mu_ip_server_shutdown (srv); /* FIXME: does it harm for MU_IP_UDP? */
750 mu_m_server_restore_signals (pconf->msrv);
751 status = pconf->msrv->conn (fd, sa, salen, pconf,
752 pconf->msrv->data);
753 closelog ();
754 exit (status);
755 }
756 else
757 {
758 register_child (pconf->msrv, pid);
759 }
760 }
761 else if (!pconf->msrv->prefork
762 || pconf->msrv->prefork (fd, sa, salen, pconf,
763 pconf->msrv->data) == 0)
764 pconf->msrv->conn (fd, sa, salen, pconf, pconf->msrv->data);
765 return 0;
766 }
767
768
769 int
mu_m_server_parse_url(mu_m_server_t msrv,const char * arg,struct mu_sockaddr ** psa)770 mu_m_server_parse_url (mu_m_server_t msrv, const char *arg,
771 struct mu_sockaddr **psa)
772 {
773 int rc;
774 mu_url_t url, url_hint;
775
776 if (arg[0] == '/')
777 url_hint = NULL;
778 else
779 {
780 rc = mu_url_create (&url_hint, "inet://");
781 if (rc)
782 return rc;
783 }
784 rc = mu_url_create_hint (&url, arg, MU_URL_PARSE_DEFAULT, url_hint);
785 mu_url_destroy (&url_hint);
786 if (rc)
787 {
788 mu_error (_("cannot parse URL `%s': %s"), arg, mu_strerror (rc));
789 return rc;
790 }
791
792 msrv->hints.flags = MU_AH_PASSIVE;
793 rc = mu_sockaddr_from_url (psa, url, &msrv->hints);
794 if (rc)
795 mu_error (_("cannot create sockaddr for URL `%s': %s"), arg,
796 mu_strerror (rc));
797 mu_url_destroy (&url);
798 return rc;
799 }
800
801 static int
server_block_begin(const char * arg,mu_m_server_t msrv,void ** pdata)802 server_block_begin (const char *arg, mu_m_server_t msrv, void **pdata)
803 {
804 struct mu_sockaddr *s;
805 if (mu_m_server_parse_url (msrv, arg, &s))
806 return 1;
807 if (s->next)
808 {
809 /* FIXME: (1) Find a way to handle all addresses.
810 (2) Print which address is being used.
811 */
812 mu_diag_output (MU_DIAG_WARNING,
813 _("%s resolves to several addresses, "
814 "only the first is used"), arg);
815 mu_sockaddr_free (s->next);
816 }
817 *pdata = mu_m_server_listen (msrv, s, msrv->deftype);
818 return 0;
819 }
820
821 static int
server_section_parser(enum mu_cfg_section_stage stage,const mu_cfg_node_t * node,const char * section_label,void ** section_data,void * call_data,mu_cfg_tree_t * tree)822 server_section_parser (enum mu_cfg_section_stage stage,
823 const mu_cfg_node_t *node,
824 const char *section_label, void **section_data,
825 void *call_data,
826 mu_cfg_tree_t *tree)
827 {
828 switch (stage)
829 {
830 case mu_cfg_section_start:
831 {
832 if (node->label == NULL || node->label->type != MU_CFG_STRING)
833 return 1;
834 /* FIXME: should not modify 2nd arg, or it should not be const */
835 return server_block_begin (node->label->v.string,
836 *section_data, section_data);
837 }
838 break;
839
840 case mu_cfg_section_end:
841 {
842 struct mu_srv_config *pconf = *section_data;
843 if (pconf->acl)
844 mu_ip_server_set_acl (pconf->tcpsrv, pconf->acl);
845 }
846 break;
847 }
848 return 0;
849 }
850
851 static int
_cb_daemon_mode(void * data,mu_config_value_t * val)852 _cb_daemon_mode (void *data, mu_config_value_t *val)
853 {
854 int *pmode = data;
855
856 if (mu_cfg_assert_value_type (val, MU_CFG_STRING))
857 return 1;
858 if (strcmp (val->v.string, "inetd") == 0
859 || strcmp (val->v.string, "interactive") == 0)
860 *pmode = MODE_INTERACTIVE;
861 else if (strcmp (val->v.string, "daemon") == 0)
862 *pmode = MODE_DAEMON;
863 else
864 {
865 mu_error (_("unknown daemon mode"));
866 return 1;
867 }
868 return 0;
869 }
870
871 unsigned short
get_port(const char * p)872 get_port (const char *p)
873 {
874 if (p)
875 {
876 char *q;
877 unsigned long n = strtoul (p, &q, 0);
878 if (*q == 0)
879 {
880 if (n > USHRT_MAX)
881 {
882 mu_error (_("invalid port number: %s"), p);
883 return 1;
884 }
885
886 return n;
887 }
888 else
889 {
890 struct servent *sp = getservbyname (p, "tcp");
891 if (!sp)
892 return 0;
893 return ntohs (sp->s_port);
894 }
895 }
896 return 0;
897 }
898
899 static int
_cb_port(void * data,mu_config_value_t * val)900 _cb_port (void *data, mu_config_value_t *val)
901 {
902 struct mu_sockaddr_hints *hp = data;
903 unsigned short num;
904
905 if (mu_cfg_assert_value_type (val, MU_CFG_STRING))
906 return 1;
907 num = get_port (val->v.string);
908 if (!num)
909 return 1;
910 hp->port = num;
911 return 0;
912 }
913
914 static struct mu_cfg_param dot_server_cfg_param[] = {
915 { "max-children", mu_c_size,
916 NULL, mu_offsetof (struct _mu_m_server,max_children), NULL,
917 N_("Maximum number of children processes to run simultaneously.") },
918 { "mode", mu_cfg_callback,
919 NULL, mu_offsetof (struct _mu_m_server,mode), _cb_daemon_mode,
920 N_("Set operation mode."),
921 /* TRANSLATORS: Words to the right of : are keywords. */
922 N_("mode: inetd|interactive|daemon") },
923 { "foreground", mu_c_bool,
924 NULL, mu_offsetof (struct _mu_m_server, foreground), NULL,
925 N_("Run in foreground.") },
926 { "pidfile", mu_c_string,
927 NULL, mu_offsetof (struct _mu_m_server,pidfile), NULL,
928 N_("Store PID of the master process in this file."),
929 N_("file") },
930 { "port", mu_cfg_callback,
931 NULL, mu_offsetof (struct _mu_m_server, hints), _cb_port,
932 N_("Default port number."),
933 N_("arg: port number or service name") },
934 { "timeout", mu_c_time,
935 NULL, mu_offsetof (struct _mu_m_server,timeout), NULL,
936 N_("Set idle timeout.") },
937 { "server", mu_cfg_section, NULL, 0, NULL,
938 N_("Server configuration.") },
939 { "acl", mu_cfg_section, NULL, mu_offsetof (struct _mu_m_server,acl), NULL,
940 N_("Per-server access control list") },
941 { NULL }
942 };
943
944 static struct mu_cfg_param server_cfg_param[] = {
945 { "single-process", mu_c_bool,
946 NULL, mu_offsetof (struct mu_srv_config, single_process), NULL,
947 N_("Do not spawn sub-process to handle requests in this server.") },
948 { "transcript", mu_c_bool,
949 NULL, mu_offsetof (struct mu_srv_config, transcript), NULL,
950 N_("Log the session transcript.") },
951 { "timeout", mu_c_time,
952 NULL, mu_offsetof (struct mu_srv_config, timeout), NULL,
953 N_("Set idle timeout.") },
954 { "acl", mu_cfg_section,
955 NULL, mu_offsetof (struct mu_srv_config, acl), NULL,
956 N_("Global access control list.") },
957 { NULL }
958 };
959
960 static int
_cb_backlog(void * data,mu_config_value_t * val)961 _cb_backlog (void *data, mu_config_value_t *val)
962 {
963 mu_ip_server_t *psrv = data;
964 int backlog;
965
966 if (mu_cfg_assert_value_type (val, MU_CFG_STRING))
967 return 1;
968 if (sscanf (val->v.string, "%d", &backlog) != 1 || backlog <= 0
969 || mu_tcp_server_set_backlog (*psrv, backlog))
970 {
971 mu_error (_("invalid argument"));
972 return 1;
973 }
974 return 0;
975 }
976
977 static struct mu_cfg_param server_tcp_param[] = {
978 { "backlog", mu_cfg_callback,
979 NULL, mu_offsetof (struct mu_srv_config, tcpsrv), _cb_backlog,
980 N_("Size of the queue of pending connections"),
981 N_("number") },
982 { NULL }
983 };
984
985 void
mu_m_server_cfg_init(mu_m_server_t srv,struct mu_cfg_param * app_param)986 mu_m_server_cfg_init (mu_m_server_t srv, struct mu_cfg_param *app_param)
987 {
988 struct mu_cfg_section *section;
989 if (mu_create_canned_section ("server", §ion) == 0)
990 {
991 section->parser = server_section_parser;
992 section->label = N_("ipaddr[:port]");
993 mu_cfg_section_add_params (section, server_cfg_param);
994 if (srv->deftype == MU_IP_TCP)
995 mu_cfg_section_add_params (section, server_tcp_param);
996 if (app_param)
997 mu_cfg_section_add_params (section, app_param);
998 }
999 if (mu_create_canned_section (".server", §ion) == 0)
1000 {
1001 mu_cfg_section_add_params (section, dot_server_cfg_param);
1002 }
1003 }
1004
1005
1006
1007