Commit 77d0b9df 77d0b9dffcee9761077828fb1725314590bff3e7 by Sergey Poznyakoff

* TODO, NEWS: Update.

* mailbox/msrv.c: New file.
* mailbox/Makefile.am: Add msrv.c.
* include/mailutils/server.h (mu_tcp_server_conn_fp): Take
sockaddr as argument
(mu_tcp_server_create,mu_tcp_server_get_sockaddr): Likewise.
(mu_m_server_*): New prototypes.
* include/mailutils/types.hin (mu_m_server_t): New type.
* mailbox/acl.c: Fix debugging output.
(mu_sockaddr_to_str, mu_sockaddr_to_astr): New functions.

* mailbox/tcpsrv.c: Handle AF_INET and AF_UNIX sockets.
* examples/echosrv.c: Update mu_tcp_server_* calls.
* examples/config/Makefile.am: Remove comsat.conf and
mailutils.rc.

* imap4d/imap4d.c, imap4d/imap4d.h, imap4d/signal.c,
maidag/lmtp.c, maidag/maidag.c, maidag/maidag.h, pop3d/extra.c,
pop3d/pop3d.c, pop3d/pop3d.h, pop3d/signal.c: Rewrite using
m-server.

* include/mailutils/cfg.h (mu_offsetof): Bug fix.
* mailbox/cfg_driver.c (dup_container): Bugfix. Offset was not
copied.
(mu_cfg_section_add_params): If identifier starts with a dot, it
is hidden, i.e. its substatements are copied directly into the
parent structure.
* mailbox/cfg_lexer.c (isword): Take care of opening braces.
(default_lexer): Several fixes.
* mailbox/cfg_parser.y (mu_cfg_parse): Initialize debugging level
from global settings.
(_scan_tree_helper): Ensure debugging object has correct locus
information before calling the section parser.
(mu_cfg_scan_tree): If no debugging object is supplied, use the
one from diag.c
* mailbox/daemon.c (mu_daemon_create_pidfile): Return a meaningful
error code.
* mailbox/debug.c (mu_debug_create): Initialize printer to NULL.
(mu_debug_vprintf): If printer is NULL, use
mu_debug_default_printer.
(mu_debug_check_level): Bugfix.

* mailbox/server.c: Minor indentation fix.
* mailbox/syslog.c (mu_diag_syslog_printer): Chop off \r as well.
* mailbox/folder.c (mu_folder_create_from_record): Bugfixes.

* include/mailutils/debug.hm4 (mu_sockaddr_to_str)
(mu_sockaddr_to_astr): New functions.

* include/mailutils/.cvsignore: Add debug.h

* po/POTFILES.in: Update.
1 parent c060b5fd
1 2008-01-04 Sergey Poznyakoff <gray@gnu.org.ua>
2
3 * TODO, NEWS: Update.
4 * mailbox/msrv.c: New file.
5 * mailbox/Makefile.am: Add msrv.c.
6 * include/mailutils/server.h (mu_tcp_server_conn_fp): Take
7 sockaddr as argument
8 (mu_tcp_server_create,mu_tcp_server_get_sockaddr): Likewise.
9 (mu_m_server_*): New prototypes.
10 * include/mailutils/types.hin (mu_m_server_t): New type.
11 * mailbox/acl.c: Fix debugging output.
12 (mu_sockaddr_to_str, mu_sockaddr_to_astr): New functions.
13
14 * mailbox/tcpsrv.c: Handle AF_INET and AF_UNIX sockets.
15 * examples/echosrv.c: Update mu_tcp_server_* calls.
16 * examples/config/Makefile.am: Remove comsat.conf and
17 mailutils.rc.
18
19 * imap4d/imap4d.c, imap4d/imap4d.h, imap4d/signal.c,
20 maidag/lmtp.c, maidag/maidag.c, maidag/maidag.h, pop3d/extra.c,
21 pop3d/pop3d.c, pop3d/pop3d.h, pop3d/signal.c: Rewrite using
22 m-server.
23
24 * include/mailutils/cfg.h (mu_offsetof): Bug fix.
25 * mailbox/cfg_driver.c (dup_container): Bugfix. Offset was not
26 copied.
27 (mu_cfg_section_add_params): If identifier starts with a dot, it
28 is hidden, i.e. its substatements are copied directly into the
29 parent structure.
30 * mailbox/cfg_lexer.c (isword): Take care of opening braces.
31 (default_lexer): Several fixes.
32 * mailbox/cfg_parser.y (mu_cfg_parse): Initialize debugging level
33 from global settings.
34 (_scan_tree_helper): Ensure debugging object has correct locus
35 information before calling the section parser.
36 (mu_cfg_scan_tree): If no debugging object is supplied, use the
37 one from diag.c
38 * mailbox/daemon.c (mu_daemon_create_pidfile): Return a meaningful
39 error code.
40 * mailbox/debug.c (mu_debug_create): Initialize printer to NULL.
41 (mu_debug_vprintf): If printer is NULL, use
42 mu_debug_default_printer.
43 (mu_debug_check_level): Bugfix.
44
45 * mailbox/server.c: Minor indentation fix.
46 * mailbox/syslog.c (mu_diag_syslog_printer): Chop off \r as well.
47 * mailbox/folder.c (mu_folder_create_from_record): Bugfixes.
48
49 * include/mailutils/debug.hm4 (mu_sockaddr_to_str)
50 (mu_sockaddr_to_astr): New functions.
51
52 * include/mailutils/.cvsignore: Add debug.h
53
54 * po/POTFILES.in: Update.
55
1 2008-01-02 Sergey Poznyakoff <gray@gnu.org.ua> 56 2008-01-02 Sergey Poznyakoff <gray@gnu.org.ua>
2 57
3 * include/mailutils/property.h: Update 58 * include/mailutils/property.h: Update
......
1 GNU mailutils NEWS -- history of user-visible changes. 2007-12-30 1 GNU mailutils NEWS -- history of user-visible changes. 2008-01-04
2 Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. 2 Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
3 See the end of file for copying conditions. 3 See the end of file for copying conditions.
4 4
...@@ -72,6 +72,11 @@ pop3d, maidag). The support is controlled at compile time by the ...@@ -72,6 +72,11 @@ pop3d, maidag). The support is controlled at compile time by the
72 is enabled if libwrap presence is detected. A set of configuration 72 is enabled if libwrap presence is detected. A set of configuration
73 file statements are provided for fine tuning TCP wrappers at run-time. 73 file statements are provided for fine tuning TCP wrappers at run-time.
74 74
75 ** pop3d and imap4d ports.
76
77 Pop3d and imap4d can be configured to listen on several different
78 IP addresses/ports (or even local sockets) simultaneously.
79
75 ** pop3d: Fixed APOP handling. 80 ** pop3d: Fixed APOP handling.
76 81
77 ** imap4d supports PREAUTH mode. 82 ** imap4d supports PREAUTH mode.
......
1 GNU mailutils TODO list. 2007-12-28 1 GNU mailutils TODO list. 2008-01-03
2 Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2 Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006,
3 2007 Free Software Foundation, Inc. 3 2007, 2008 Free Software Foundation, Inc.
4
5 * Configuration callback functions should not modify node->tag and node->label.
6
7 * Debug handling in cfg vs. argp
4 8
5 * Fix folder_imap_list in libproto/imap/folder.c 9 * Fix folder_imap_list in libproto/imap/folder.c
6 10
......
...@@ -18,10 +18,8 @@ ...@@ -18,10 +18,8 @@
18 ## 02110-1301 USA 18 ## 02110-1301 USA
19 19
20 EXTRA_DIST = \ 20 EXTRA_DIST = \
21 comsat.conf\
22 dot.biffrc\ 21 dot.biffrc\
23 gnu-imap4d.pam\ 22 gnu-imap4d.pam\
24 gnu-pop3d.pam\ 23 gnu-pop3d.pam\
25 mailutils.dict\ 24 mailutils.dict
26 mailutils.rc
27 25
......
...@@ -35,15 +35,17 @@ ...@@ -35,15 +35,17 @@
35 mu_server_t server; 35 mu_server_t server;
36 36
37 int 37 int
38 echo_conn (int fd, struct sockaddr_in *s, void *server_data, void *call_data, 38 echo_conn (int fd, struct sockaddr *s, int len,
39 void *server_data, void *call_data,
39 mu_tcp_server_t srv) 40 mu_tcp_server_t srv)
40 { 41 {
41 struct sockaddr_in srv_addr; 42 struct sockaddr_in srv_addr, *s_in = (struct sockaddr_in *)s;
43 int addrlen = sizeof srv_addr;
42 pid_t pid; 44 pid_t pid;
43 char buf[512]; 45 char buf[512];
44 FILE *in, *out; 46 FILE *in, *out;
45 47
46 mu_tcp_server_get_sockaddr (srv, &srv_addr); 48 mu_tcp_server_get_sockaddr (srv, (struct sockaddr *)&srv_addr, &addrlen);
47 49
48 pid = fork (); 50 pid = fork ();
49 if (pid == -1) 51 if (pid == -1)
...@@ -57,7 +59,7 @@ echo_conn (int fd, struct sockaddr_in *s, void *server_data, void *call_data, ...@@ -57,7 +59,7 @@ echo_conn (int fd, struct sockaddr_in *s, void *server_data, void *call_data,
57 mu_diag_output (MU_DIAG_INFO, "%lu: opened connection %s:%d => %s:%d", 59 mu_diag_output (MU_DIAG_INFO, "%lu: opened connection %s:%d => %s:%d",
58 (unsigned long) pid, 60 (unsigned long) pid,
59 inet_ntoa (srv_addr.sin_addr), ntohs (srv_addr.sin_port), 61 inet_ntoa (srv_addr.sin_addr), ntohs (srv_addr.sin_port),
60 inet_ntoa (s->sin_addr), ntohs (s->sin_port)); 62 inet_ntoa (s_in->sin_addr), ntohs (s_in->sin_port));
61 return 0; 63 return 0;
62 } 64 }
63 65
...@@ -132,7 +134,7 @@ create_server (char *arg) ...@@ -132,7 +134,7 @@ create_server (char *arg)
132 } 134 }
133 s.sin_port = htons (n); 135 s.sin_port = htons (n);
134 136
135 MU_ASSERT (mu_tcp_server_create (&tcpsrv, &s)); 137 MU_ASSERT (mu_tcp_server_create (&tcpsrv, (struct sockaddr*) &s, sizeof s));
136 MU_ASSERT (mu_tcp_server_open (tcpsrv)); 138 MU_ASSERT (mu_tcp_server_open (tcpsrv));
137 MU_ASSERT (mu_tcp_server_set_conn (tcpsrv, echo_conn)); 139 MU_ASSERT (mu_tcp_server_set_conn (tcpsrv, echo_conn));
138 MU_ASSERT (mu_server_add_connection (server, 140 MU_ASSERT (mu_server_add_connection (server,
......
...@@ -377,7 +377,7 @@ com_verbose (char *arg) ...@@ -377,7 +377,7 @@ com_verbose (char *arg)
377 { 377 {
378 mu_debug_t debug; 378 mu_debug_t debug;
379 mu_debug_create (&debug, NULL); 379 mu_debug_create (&debug, NULL);
380 mu_debug_set_level (debug, MU_DEBUG_PROT); 380 mu_debug_set_level (debug, MU_DEBUG_LEVEL_UPTO (MU_DEBUG_PROT));
381 status = mu_nntp_set_debug (nntp, debug); 381 status = mu_nntp_set_debug (nntp, debug);
382 } 382 }
383 else 383 else
......
...@@ -364,7 +364,7 @@ com_verbose (char *arg) ...@@ -364,7 +364,7 @@ com_verbose (char *arg)
364 { 364 {
365 mu_debug_t debug; 365 mu_debug_t debug;
366 mu_debug_create (&debug, NULL); 366 mu_debug_create (&debug, NULL);
367 mu_debug_set_level (debug, MU_DEBUG_PROT); 367 mu_debug_set_level (debug, MU_DEBUG_LEVEL_UPTO (MU_DEBUG_PROT));
368 status = mu_pop3_set_debug (pop3, debug); 368 status = mu_pop3_set_debug (pop3, debug);
369 } 369 }
370 else 370 else
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail 1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 1999, 2001, 2002, 2003, 2004, 2 Copyright (C) 1999, 2001, 2002, 2003, 2004,
3 2005, 2006, 2007 Free Software Foundation, Inc. 3 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
4 4
5 GNU Mailutils is free software; you can redistribute it and/or modify 5 GNU Mailutils is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by 6 it under the terms of the GNU General Public License as published by
...@@ -24,20 +24,15 @@ ...@@ -24,20 +24,15 @@
24 #include "mailutils/libargp.h" 24 #include "mailutils/libargp.h"
25 #include "tcpwrap.h" 25 #include "tcpwrap.h"
26 26
27 mu_m_server_t server;
28 unsigned int idle_timeout;
29 int imap4d_transcript;
30
27 mu_mailbox_t mbox; 31 mu_mailbox_t mbox;
28 char *homedir; 32 char *homedir;
29 int state = STATE_NONAUTH; 33 int state = STATE_NONAUTH;
30 struct mu_auth_data *auth_data; 34 struct mu_auth_data *auth_data;
31 35
32 struct mu_gocs_daemon default_gocs_daemon = {
33 MODE_INTERACTIVE, /* Start in interactive (inetd) mode */
34 20, /* Default maximum number of children */
35 143, /* Standard IMAP4 port */
36 1800, /* RFC2060: 30 minutes. */
37 0, /* No transcript by default */
38 NULL /* No PID file by default */
39 };
40
41 int login_disabled; /* Disable LOGIN command */ 36 int login_disabled; /* Disable LOGIN command */
42 int tls_required; /* Require STARTTLS */ 37 int tls_required; /* Require STARTTLS */
43 int create_home_dir; /* Create home directory if it does not 38 int create_home_dir; /* Create home directory if it does not
...@@ -51,33 +46,34 @@ int ident_port; ...@@ -51,33 +46,34 @@ int ident_port;
51 char *ident_keyfile; 46 char *ident_keyfile;
52 int ident_encrypt_only; 47 int ident_encrypt_only;
53 48
54 mu_acl_t imap4d_acl;
55
56 /* Number of child processes. */
57 size_t children;
58
59 const char *program_version = "imap4d (" PACKAGE_STRING ")"; 49 const char *program_version = "imap4d (" PACKAGE_STRING ")";
60 static char doc[] = N_("GNU imap4d -- the IMAP4D daemon"); 50 static char doc[] = N_("GNU imap4d -- the IMAP4D daemon");
61 51
62 #define ARG_LOGIN_DISABLED 256 52 #define OPT_LOGIN_DISABLED 256
63 #define ARG_TLS_REQUIRED 257 53 #define OPT_TLS_REQUIRED 257
64 #define ARG_CREATE_HOME_DIR 258 54 #define OPT_CREATE_HOME_DIR 258
65 #define ARG_OPTION_PREAUTH 259 55 #define OPT_PREAUTH 259
56 #define OPT_FOREGROUND 260
66 57
67 static struct argp_option options[] = { 58 static struct argp_option options[] = {
59 { "foreground", OPT_FOREGROUND, 0, 0, N_("Remain in foreground."), 0},
60 { "inetd", 'i', 0, 0, N_("Run in inetd mode"), 0},
61 { "daemon", 'd', N_("NUMBER"), OPTION_ARG_OPTIONAL,
62 N_("Runs in daemon mode with a maximum of NUMBER children"), 0 },
63
68 {"other-namespace", 'O', N_("PATHLIST"), OPTION_HIDDEN, 64 {"other-namespace", 'O', N_("PATHLIST"), OPTION_HIDDEN,
69 N_("Set the `other' namespace"), 0}, 65 N_("Set the `other' namespace"), 0},
70 {"shared-namespace", 'S', N_("PATHLIST"), OPTION_HIDDEN, 66 {"shared-namespace", 'S', N_("PATHLIST"), OPTION_HIDDEN,
71 N_("Set the `shared' namespace"), 0}, 67 N_("Set the `shared' namespace"), 0},
72 {"login-disabled", ARG_LOGIN_DISABLED, NULL, OPTION_HIDDEN, 68 {"login-disabled", OPT_LOGIN_DISABLED, NULL, OPTION_HIDDEN,
73 N_("Disable LOGIN command")}, 69 N_("Disable LOGIN command")},
74 {"create-home-dir", ARG_CREATE_HOME_DIR, N_("MODE"), 70 {"create-home-dir", OPT_CREATE_HOME_DIR, N_("MODE"),
75 OPTION_ARG_OPTIONAL|OPTION_HIDDEN, 71 OPTION_ARG_OPTIONAL|OPTION_HIDDEN,
76 N_("Create home directory, if it does not exist")}, 72 N_("Create home directory, if it does not exist")},
77 {"preauth", ARG_OPTION_PREAUTH, NULL, 0, 73 {"preauth", OPT_PREAUTH, NULL, 0,
78 N_("Start in preauth mode") }, 74 N_("Start in preauth mode") },
79 #ifdef WITH_TLS 75 #ifdef WITH_TLS
80 {"tls-required", ARG_TLS_REQUIRED, NULL, OPTION_HIDDEN, 76 {"tls-required", OPT_TLS_REQUIRED, NULL, OPTION_HIDDEN,
81 N_("Always require STARTTLS before entering authentication phase")}, 77 N_("Always require STARTTLS before entering authentication phase")},
82 #endif 78 #endif
83 {NULL, 0, NULL, 0, NULL, 0} 79 {NULL, 0, NULL, 0, NULL, 0}
...@@ -97,7 +93,6 @@ static struct argp argp = { ...@@ -97,7 +93,6 @@ static struct argp argp = {
97 }; 93 };
98 94
99 static const char *imap4d_capa[] = { 95 static const char *imap4d_capa[] = {
100 "daemon",
101 "auth", 96 "auth",
102 "common", 97 "common",
103 "debug", 98 "debug",
...@@ -108,8 +103,6 @@ static const char *imap4d_capa[] = { ...@@ -108,8 +103,6 @@ static const char *imap4d_capa[] = {
108 NULL 103 NULL
109 }; 104 };
110 105
111 static void imap4d_daemon_init (void);
112 static void imap4d_daemon (unsigned int, unsigned int);
113 static int imap4d_mainloop (int, FILE *, FILE *); 106 static int imap4d_mainloop (int, FILE *, FILE *);
114 107
115 static error_t 108 static error_t
...@@ -119,6 +112,20 @@ imap4d_parse_opt (int key, char *arg, struct argp_state *state) ...@@ -119,6 +112,20 @@ imap4d_parse_opt (int key, char *arg, struct argp_state *state)
119 112
120 switch (key) 113 switch (key)
121 { 114 {
115 case 'd':
116 mu_argp_node_list_new (&lst, "mode", "daemon");
117 if (arg)
118 mu_argp_node_list_new (&lst, "max-children", arg);
119 break;
120
121 case 'i':
122 mu_argp_node_list_new (&lst, "mode", "inetd");
123 break;
124
125 case OPT_FOREGROUND:
126 mu_argp_node_list_new (&lst, "foreground", "yes");
127 break;
128
122 case 'O': 129 case 'O':
123 mu_argp_node_list_new (&lst, "other-namespace", arg); 130 mu_argp_node_list_new (&lst, "other-namespace", arg);
124 break; 131 break;
...@@ -127,23 +134,23 @@ imap4d_parse_opt (int key, char *arg, struct argp_state *state) ...@@ -127,23 +134,23 @@ imap4d_parse_opt (int key, char *arg, struct argp_state *state)
127 mu_argp_node_list_new (&lst, "shared-namespace", arg); 134 mu_argp_node_list_new (&lst, "shared-namespace", arg);
128 break; 135 break;
129 136
130 case ARG_LOGIN_DISABLED: 137 case OPT_LOGIN_DISABLED:
131 mu_argp_node_list_new (&lst, "login-disabled", "yes"); 138 mu_argp_node_list_new (&lst, "login-disabled", "yes");
132 break; 139 break;
133 140
134 case ARG_CREATE_HOME_DIR: 141 case OPT_CREATE_HOME_DIR:
135 mu_argp_node_list_new (&lst, "create-home-dir", "yes"); 142 mu_argp_node_list_new (&lst, "create-home-dir", "yes");
136 if (arg) 143 if (arg)
137 mu_argp_node_list_new (&lst, "home-dir-mode", arg); 144 mu_argp_node_list_new (&lst, "home-dir-mode", arg);
138 break; 145 break;
139 146
140 #ifdef WITH_TLS 147 #ifdef WITH_TLS
141 case ARG_TLS_REQUIRED: 148 case OPT_TLS_REQUIRED:
142 mu_argp_node_list_new (&lst, "tls-required", "yes"); 149 mu_argp_node_list_new (&lst, "tls-required", "yes");
143 break; 150 break;
144 #endif 151 #endif
145 152
146 case ARG_OPTION_PREAUTH: 153 case OPT_PREAUTH:
147 preauth_mode = preauth_stdio; 154 preauth_mode = preauth_stdio;
148 break; 155 break;
149 156
...@@ -309,140 +316,13 @@ static struct mu_cfg_param imap4d_cfg_param[] = { ...@@ -309,140 +316,13 @@ static struct mu_cfg_param imap4d_cfg_param[] = {
309 N_("Name of DES keyfile for decoding ecrypted ident responses.") }, 316 N_("Name of DES keyfile for decoding ecrypted ident responses.") },
310 { "ident-entrypt-only", mu_cfg_bool, &ident_encrypt_only, 0, NULL, 317 { "ident-entrypt-only", mu_cfg_bool, &ident_encrypt_only, 0, NULL,
311 N_("Use only encrypted ident responses.") }, 318 N_("Use only encrypted ident responses.") },
312 { "acl", mu_cfg_section, }, 319 { ".server", mu_cfg_section, NULL, 0, NULL,
320 N_("Server configuration.") },
313 TCP_WRAPPERS_CONFIG 321 TCP_WRAPPERS_CONFIG
314 { NULL } 322 { NULL }
315 }; 323 };
316 324
317 int 325 int
318 main (int argc, char **argv)
319 {
320 struct group *gr;
321 int status = EXIT_SUCCESS;
322
323 /* Native Language Support */
324 mu_init_nls ();
325
326 state = STATE_NONAUTH; /* Starting state in non-auth. */
327
328 MU_AUTH_REGISTER_ALL_MODULES ();
329 /* Register the desired formats. */
330 mu_register_local_mbox_formats ();
331
332 imap4d_capability_init ();
333 mu_gocs_daemon = default_gocs_daemon;
334 #ifdef WITH_TLS
335 mu_gocs_register ("tls", mu_tls_module_init);
336 #endif /* WITH_TLS */
337 #ifdef WITH_GSASL
338 mu_gocs_register ("gsasl", mu_gsasl_module_init);
339 #endif
340 mu_tcpwrapper_cfg_init ();
341 mu_acl_cfg_init ();
342 mu_argp_init (program_version, NULL);
343 if (mu_app_init (&argp, imap4d_capa, imap4d_cfg_param,
344 argc, argv, 0, NULL, &imap4d_acl))
345 exit (1);
346
347 if (login_disabled)
348 imap4d_capability_add (IMAP_CAPA_LOGINDISABLED);
349 #ifdef WITH_TLS
350 if (tls_required)
351 imap4d_capability_add (IMAP_CAPA_XTLSREQUIRED);
352 #endif
353
354 auth_gssapi_init ();
355 auth_gsasl_init ();
356
357 #ifdef USE_LIBPAM
358 if (!mu_pam_service)
359 mu_pam_service = "gnu-imap4d";
360 #endif
361
362 if (mu_gocs_daemon.mode == MODE_DAEMON)
363 {
364 /* Normal operation: */
365 /* First we want our group to be mail so we can access the spool. */
366 gr = getgrnam ("mail");
367 if (gr == NULL)
368 {
369 perror (_("Error getting mail group"));
370 exit (1);
371 }
372
373 if (setgid (gr->gr_gid) == -1)
374 {
375 perror (_("Error setting mail group"));
376 exit (1);
377 }
378 }
379
380 /* Set the signal handlers. */
381 signal (SIGINT, imap4d_signal);
382 signal (SIGQUIT, imap4d_signal);
383 signal (SIGILL, imap4d_signal);
384 signal (SIGBUS, imap4d_signal);
385 signal (SIGFPE, imap4d_signal);
386 signal (SIGSEGV, imap4d_signal);
387 signal (SIGTERM, imap4d_signal);
388 signal (SIGSTOP, imap4d_signal);
389 signal (SIGPIPE, imap4d_signal);
390 /*signal (SIGPIPE, SIG_IGN); */
391 signal (SIGABRT, imap4d_signal);
392
393 if (mu_gocs_daemon.mode == MODE_DAEMON)
394 imap4d_daemon_init ();
395 else
396 {
397 /* Make sure we are in the root. */
398 chdir ("/");
399 }
400
401 /* Set up for syslog. */
402 openlog ("gnu-imap4d", LOG_PID, log_facility);
403
404 /* Redirect any stdout error from the library to syslog, they
405 should not go to the client. */
406 {
407 mu_debug_t debug;
408
409 mu_diag_get_debug (&debug);
410 mu_debug_set_print (debug, mu_diag_syslog_printer, NULL);
411
412 /* FIXME: this should be done automatically by cfg */
413 if (imap4d_acl)
414 {
415 mu_acl_get_debug (imap4d_acl, &debug);
416 mu_debug_set_print (debug, mu_debug_syslog_printer, NULL);
417 }
418 }
419
420 umask (S_IROTH | S_IWOTH | S_IXOTH); /* 007 */
421
422 if (mu_gocs_daemon.pidfile)
423 {
424 mu_daemon_create_pidfile (mu_gocs_daemon.pidfile);
425 }
426
427 /* Check TLS environment, i.e. cert and key files */
428 #ifdef WITH_TLS
429 starttls_init ();
430 #endif /* WITH_TLS */
431
432 /* Actually run the daemon. */
433 if (mu_gocs_daemon.mode == MODE_DAEMON)
434 imap4d_daemon (mu_gocs_daemon.maxchildren, mu_gocs_daemon.port);
435 /* exit (0) -- no way out of daemon except a signal. */
436 else
437 status = imap4d_mainloop (fileno (stdin), stdin, stdout);
438
439 /* Close the syslog connection and exit. */
440 closelog ();
441
442 return status;
443 }
444
445 int
446 imap4d_session_setup0 () 326 imap4d_session_setup0 ()
447 { 327 {
448 homedir = mu_normalize_path (strdup (auth_data->dir), "/"); 328 homedir = mu_normalize_path (strdup (auth_data->dir), "/");
...@@ -499,44 +379,13 @@ imap4d_mainloop (int fd, FILE *infile, FILE *outfile) ...@@ -499,44 +379,13 @@ imap4d_mainloop (int fd, FILE *infile, FILE *outfile)
499 { 379 {
500 if (get_client_address (fd, &cs) == 0) 380 if (get_client_address (fd, &cs) == 0)
501 { 381 {
502 if (imap4d_acl)
503 {
504 mu_acl_result_t res;
505 int rc = mu_acl_check_sockaddr (imap4d_acl,
506 (struct sockaddr*) &cs,
507 sizeof (cs),
508 &res);
509 if (rc)
510 {
511 mu_error (_("Access from %s blocked: cannot check ACLs: %s"),
512 inet_ntoa (cs.sin_addr), mu_strerror (rc));
513 return 1;
514 }
515 switch (res)
516 {
517 case mu_acl_result_undefined:
518 mu_diag_output (MU_DIAG_INFO,
519 _("%s: undefined ACL result; access allowed"),
520 inet_ntoa (cs.sin_addr));
521 break;
522
523 case mu_acl_result_accept:
524 break;
525
526 case mu_acl_result_deny:
527 mu_error (_("Access from %s blocked."),
528 inet_ntoa (cs.sin_addr));
529 return 1;
530 }
531 }
532
533 if (!mu_tcpwrapper_access (fd)) 382 if (!mu_tcpwrapper_access (fd))
534 { 383 {
535 mu_error (_("Access from %s blocked."), inet_ntoa (cs.sin_addr)); 384 mu_error (_("Access from %s blocked."), inet_ntoa (cs.sin_addr));
536 return 1; 385 return 1;
537 } 386 }
538 } 387 }
539 else if (mu_tcp_wrapper_enable || imap4d_acl) 388 else if (mu_tcp_wrapper_enable)
540 { 389 {
541 mu_error (_("Rejecting connection from unknown address")); 390 mu_error (_("Rejecting connection from unknown address"));
542 return 1; 391 return 1;
...@@ -584,145 +433,172 @@ imap4d_mainloop (int fd, FILE *infile, FILE *outfile) ...@@ -584,145 +433,172 @@ imap4d_mainloop (int fd, FILE *infile, FILE *outfile)
584 return EXIT_SUCCESS; 433 return EXIT_SUCCESS;
585 } 434 }
586 435
587 /* Sets things up for daemon mode. */ 436 int
588 static void 437 imap4d_connection (int fd, void *data, time_t timeout, int transcript)
589 imap4d_daemon_init (void)
590 { 438 {
591 extern int daemon (int, int); 439 idle_timeout = timeout;
440 imap4d_transcript = transcript;
441 imap4d_mainloop (fd, fdopen (fd, "r"), fdopen (fd, "w"));
442 return 0;
443 }
592 444
593 /* Become a daemon. Take care to close inherited fds and to hold 445 int
594 first three one, in, out, err */ 446 imap4d_check_home_dir (const char *dir, uid_t uid, gid_t gid)
595 if (daemon (0, 0) < 0) 447 {
448 struct stat st;
449
450 if (stat (homedir, &st))
596 { 451 {
597 perror (_("could not become daemon")); 452 if (errno == ENOENT && create_home_dir)
598 exit (1); 453 {
454 mode_t mode = umask (0);
455 int rc = mkdir (homedir, home_dir_mode);
456 umask (mode);
457 if (rc)
458 {
459 mu_error ("Cannot create home directory `%s': %s",
460 homedir, mu_strerror (errno));
461 return 1;
599 } 462 }
600 463 if (chown (homedir, uid, gid))
601 /* SIGCHLD is not ignore but rather use to do some simple load balancing. */
602 #ifdef HAVE_SIGACTION
603 { 464 {
604 struct sigaction act; 465 mu_error ("Cannot set owner for home directory `%s': %s",
605 act.sa_handler = imap4d_sigchld; 466 homedir, mu_strerror (errno));
606 sigemptyset (&act.sa_mask); 467 return 1;
607 act.sa_flags = 0;
608 sigaction (SIGCHLD, &act, NULL);
609 } 468 }
610 #else 469 }
611 signal (SIGCHLD, imap4d_sigchld); 470 }
612 #endif 471
472 return 0;
613 } 473 }
614 474
615 /* Runs GNU imap4d in standalone daemon mode. This opens and binds to a port 475 int
616 (default 143) then executes a imap4d_mainloop() upon accepting a connection. 476 main (int argc, char **argv)
617 It starts maxchildren child processes to listen to and accept socket
618 connections. */
619 static void
620 imap4d_daemon (unsigned int maxchildren, unsigned int port)
621 { 477 {
622 struct sockaddr_in server, client; 478 struct group *gr;
623 pid_t pid; 479 int status = EXIT_SUCCESS;
624 int listenfd, connfd;
625 size_t size;
626 480
627 listenfd = socket (PF_INET, SOCK_STREAM, 0); 481 /* Native Language Support */
628 if (listenfd == -1) 482 mu_init_nls ();
629 {
630 mu_diag_output (MU_DIAG_ERROR, "socket: %s", strerror (errno));
631 exit (1);
632 }
633 size = 1; /* Use size here to avoid making a new variable. */
634 setsockopt (listenfd, SOL_SOCKET, SO_REUSEADDR, &size, sizeof (size));
635 size = sizeof (server);
636 memset (&server, 0, size);
637 server.sin_family = AF_INET;
638 server.sin_addr.s_addr = htonl (INADDR_ANY);
639 server.sin_port = htons (port);
640
641 if (bind (listenfd, (struct sockaddr *) &server, size) == -1)
642 {
643 mu_diag_output (MU_DIAG_ERROR, "bind: %s", strerror (errno));
644 exit (1);
645 }
646 483
647 if (listen (listenfd, 128) == -1) 484 state = STATE_NONAUTH; /* Starting state in non-auth. */
648 { 485
649 mu_diag_output (MU_DIAG_ERROR, "listen: %s", strerror (errno)); 486 MU_AUTH_REGISTER_ALL_MODULES ();
487 /* Register the desired formats. */
488 mu_register_local_mbox_formats ();
489
490 imap4d_capability_init ();
491 #ifdef WITH_TLS
492 mu_gocs_register ("tls", mu_tls_module_init);
493 #endif /* WITH_TLS */
494 #ifdef WITH_GSASL
495 mu_gocs_register ("gsasl", mu_gsasl_module_init);
496 #endif
497 mu_tcpwrapper_cfg_init ();
498 mu_acl_cfg_init ();
499 mu_m_server_cfg_init ();
500
501 mu_argp_init (program_version, NULL);
502
503 mu_m_server_create (&server, "GNU imap4d");
504 mu_m_server_set_conn (server, imap4d_connection);
505 mu_m_server_set_mode (server, MODE_INTERACTIVE);
506 mu_m_server_set_max_children (server, 20);
507 /* FIXME mu_m_server_set_pidfile (); */
508 mu_m_server_set_default_port (server, 143);
509 mu_m_server_set_timeout (server, 1800); /* RFC2060: 30 minutes. */
510
511 if (mu_app_init (&argp, imap4d_capa, imap4d_cfg_param,
512 argc, argv, 0, NULL, server))
650 exit (1); 513 exit (1);
651 }
652 514
653 mu_diag_output (MU_DIAG_INFO, _("GNU imap4d started")); 515 if (login_disabled)
516 imap4d_capability_add (IMAP_CAPA_LOGINDISABLED);
517 #ifdef WITH_TLS
518 if (tls_required)
519 imap4d_capability_add (IMAP_CAPA_XTLSREQUIRED);
520 #endif
521
522 auth_gssapi_init ();
523 auth_gsasl_init ();
654 524
655 for (;;) 525 #ifdef USE_LIBPAM
656 { 526 if (!mu_pam_service)
657 if (children > maxchildren) 527 mu_pam_service = "gnu-imap4d";
528 #endif
529
530 if (mu_m_server_mode (server) == MODE_DAEMON)
658 { 531 {
659 mu_diag_output (MU_DIAG_ERROR, _("Too many children (%s)"), 532 /* Normal operation: */
660 mu_umaxtostr (0, children)); 533 /* First we want our group to be mail so we can access the spool. */
661 pause (); 534 gr = getgrnam ("mail");
662 continue; 535 if (gr == NULL)
663 }
664 connfd = accept (listenfd, (struct sockaddr *) &client,
665 (socklen_t *) & size);
666 if (connfd == -1)
667 { 536 {
668 if (errno == EINTR) 537 perror (_("Error getting mail group"));
669 continue;
670 mu_diag_output (MU_DIAG_ERROR, "accept: %s", strerror (errno));
671 exit (1); 538 exit (1);
672 } 539 }
673 540
674 pid = fork (); 541 if (setgid (gr->gr_gid) == -1)
675 if (pid == -1)
676 mu_diag_output (MU_DIAG_ERROR, "fork: %s", strerror (errno));
677 else if (pid == 0) /* Child. */
678 { 542 {
679 int status; 543 perror (_("Error setting mail group"));
544 exit (1);
545 }
546 }
680 547
681 close (listenfd); 548 /* Set the signal handlers. */
549 signal (SIGINT, imap4d_signal);
550 signal (SIGQUIT, imap4d_signal);
551 signal (SIGILL, imap4d_signal);
552 signal (SIGBUS, imap4d_signal);
553 signal (SIGFPE, imap4d_signal);
554 signal (SIGSEGV, imap4d_signal);
555 signal (SIGTERM, imap4d_signal);
556 signal (SIGSTOP, imap4d_signal);
557 signal (SIGPIPE, imap4d_signal);
558 /*signal (SIGPIPE, SIG_IGN); */
559 signal (SIGABRT, imap4d_signal);
682 560
683 status = imap4d_mainloop (connfd, 561 /* Set up for syslog. */
684 fdopen (connfd, "r"), 562 openlog ("gnu-imap4d", LOG_PID, log_facility);
685 fdopen (connfd, "w"));
686 563
687 close (connfd); 564 /* Redirect any stdout error from the library to syslog, they
688 closelog (); 565 should not go to the client. */
689 exit (status);
690 }
691 else
692 { 566 {
693 ++children; 567 mu_debug_t debug;
694 } 568
695 close (connfd); 569 mu_diag_get_debug (&debug);
570 mu_debug_set_print (debug, mu_diag_syslog_printer, NULL);
571
572 mu_debug_default_printer = mu_debug_syslog_printer;
696 } 573 }
697 }
698 574
699 int 575 umask (S_IROTH | S_IWOTH | S_IXOTH); /* 007 */
700 imap4d_check_home_dir (const char *dir, uid_t uid, gid_t gid)
701 {
702 struct stat st;
703 576
704 if (stat (homedir, &st)) 577 /* Check TLS environment, i.e. cert and key files */
705 { 578 #ifdef WITH_TLS
706 if (errno == ENOENT && create_home_dir) 579 starttls_init ();
707 { 580 #endif /* WITH_TLS */
708 mode_t mode = umask (0); 581
709 int rc = mkdir (homedir, home_dir_mode); 582 /* Actually run the daemon. */
710 umask (mode); 583 if (mu_m_server_mode (server) == MODE_DAEMON)
711 if (rc)
712 { 584 {
713 mu_error ("Cannot create home directory `%s': %s", 585 mu_m_server_begin (server);
714 homedir, mu_strerror (errno)); 586 status = mu_m_server_run (server);
715 return 1; 587 mu_m_server_end (server);
588 mu_m_server_destroy (&server);
716 } 589 }
717 if (chown (homedir, uid, gid)) 590 else
718 { 591 {
719 mu_error ("Cannot set owner for home directory `%s': %s", 592 /* Make sure we are in the root directory. */
720 homedir, mu_strerror (errno)); 593 chdir ("/");
721 return 1; 594 status = imap4d_mainloop (fileno (stdin), stdin, stdout);
722 }
723 }
724 } 595 }
725 596
726 return 0; 597 if (status)
598 mu_error (_("Main loop status: %s"), mu_strerror (status));
599 /* Close the syslog connection and exit. */
600 closelog ();
601
602 return status != 0;
727 } 603 }
728 604
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail 1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 1999, 2001, 2002, 2003, 2004, 2 Copyright (C) 1999, 2001, 2002, 2003, 2004,
3 2005, 2006, 2007 Free Software Foundation, Inc. 3 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
4 4
5 GNU Mailutils is free software; you can redistribute it and/or modify 5 GNU Mailutils is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by 6 it under the terms of the GNU General Public License as published by
...@@ -97,6 +97,7 @@ ...@@ -97,6 +97,7 @@
97 #include <mailutils/daemon.h> 97 #include <mailutils/daemon.h>
98 #include <mailutils/pam.h> 98 #include <mailutils/pam.h>
99 #include <mailutils/acl.h> 99 #include <mailutils/acl.h>
100 #include <mailutils/server.h>
100 101
101 #include <mu_asprintf.h> 102 #include <mu_asprintf.h>
102 #include <mu_umaxtostr.h> 103 #include <mu_umaxtostr.h>
......
...@@ -19,21 +19,6 @@ ...@@ -19,21 +19,6 @@
19 #define __USE_MISC 19 #define __USE_MISC
20 #include "imap4d.h" 20 #include "imap4d.h"
21 21
22 RETSIGTYPE
23 imap4d_sigchld (int signo)
24 {
25 pid_t pid;
26 int status;
27
28 while ((pid = waitpid (-1, &status, WNOHANG)) > 0)
29 --children;
30 #ifndef HAVE_SIGACTION
31 /* On some system, signal implements the unreliable semantic and
32 has to be rearm. */
33 signal (signo, imap4d_sigchld);
34 #endif
35 }
36
37 /* Default signal handler to call the imap4d_bye() function */ 22 /* Default signal handler to call the imap4d_bye() function */
38 23
39 RETSIGTYPE 24 RETSIGTYPE
......
1 /* cfg.h -- general-purpose configuration file parser 1 /* cfg.h -- general-purpose configuration file parser
2 Copyright (C) 2007 Free Software Foundation, Inc. 2 Copyright (C) 2007, 2008 Free Software Foundation, Inc.
3 3
4 GNU Mailutils is free software; you can redistribute it and/or 4 GNU Mailutils is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License as 5 modify it under the terms of the GNU General Public License as
...@@ -135,7 +135,7 @@ struct mu_cfg_param ...@@ -135,7 +135,7 @@ struct mu_cfg_param
135 const char *argname; 135 const char *argname;
136 }; 136 };
137 137
138 #define mu_offsetof(s,f) ((size_t)&((s*)0).f) 138 #define mu_offsetof(s,f) ((size_t)&((s*)0)->f)
139 139
140 #define MU_TARGET_REF(f) &f, 0 140 #define MU_TARGET_REF(f) &f, 0
141 #define MU_TARGET_OFF(s,f) NULL, mu_offsetof(s,f) 141 #define MU_TARGET_OFF(s,f) NULL, mu_offsetof(s,f)
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail -*- c -*- 1 /* GNU Mailutils -- a suite of utilities for electronic mail -*- c -*-
2 Copyright (C) 1999, 2000, 2005, 2007 Free Software Foundation, Inc. 2 Copyright (C) 1999, 2000, 2005, 2007, 2008 Free Software Foundation, Inc.
3 3
4 This library is free software; you can redistribute it and/or 4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public 5 modify it under the terms of the GNU Lesser General Public
...@@ -92,6 +92,13 @@ int mu_global_debug_from_string (const char *, const char *); ...@@ -92,6 +92,13 @@ int mu_global_debug_from_string (const char *, const char *);
92 int mu_debug_level_from_string (const char *string, mu_log_level_t *plev, 92 int mu_debug_level_from_string (const char *string, mu_log_level_t *plev,
93 mu_debug_t debug); 93 mu_debug_t debug);
94 94
95 struct sockaddr;
96 void mu_sockaddr_to_str (struct sockaddr *sa, int salen,
97 char *bufptr, size_t buflen,
98 size_t *plen);
99 char *mu_sockaddr_to_astr (struct sockaddr *sa, int salen);
100
101
95 102
96 #define MU_ASSERT(expr) \ 103 #define MU_ASSERT(expr) \
97 do \ 104 do \
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
19 #define _MAILUTILS_SERVER_H 19 #define _MAILUTILS_SERVER_H
20 20
21 #include <mailutils/types.h> 21 #include <mailutils/types.h>
22 #include <signal.h>
22 23
23 typedef int (*mu_conn_loop_fp) (int fd, void *conn_data, void *server_data); 24 typedef int (*mu_conn_loop_fp) (int fd, void *conn_data, void *server_data);
24 typedef void (*mu_conn_free_fp) (void *conn_data, void *server_data); 25 typedef void (*mu_conn_free_fp) (void *conn_data, void *server_data);
...@@ -43,15 +44,16 @@ int mu_server_count (mu_server_t srv, size_t *pcount); ...@@ -43,15 +44,16 @@ int mu_server_count (mu_server_t srv, size_t *pcount);
43 44
44 45
45 /* TCP server */ 46 /* TCP server */
46 struct sockaddr_in; 47 struct sockaddr;
47 typedef int (*mu_tcp_server_conn_fp) (int fd, struct sockaddr_in *s, 48 typedef int (*mu_tcp_server_conn_fp) (int fd, struct sockaddr *s, int len,
48 void *server_data, void *call_data, 49 void *server_data, void *call_data,
49 mu_tcp_server_t srv); 50 mu_tcp_server_t srv);
50 typedef int (*mu_tcp_server_intr_fp) (void *data, void *call_data); 51 typedef int (*mu_tcp_server_intr_fp) (void *data, void *call_data);
51 typedef void (*mu_tcp_server_free_fp) (void *data); 52 typedef void (*mu_tcp_server_free_fp) (void *data);
52 53
53 54
54 int mu_tcp_server_create (mu_tcp_server_t *psrv, struct sockaddr_in *addr); 55 int mu_tcp_server_create (mu_tcp_server_t *psrv, struct sockaddr *addr,
56 int len);
55 int mu_tcp_server_destroy (mu_tcp_server_t *psrv); 57 int mu_tcp_server_destroy (mu_tcp_server_t *psrv);
56 int mu_tcp_server_set_debug (mu_tcp_server_t srv, mu_debug_t debug); 58 int mu_tcp_server_set_debug (mu_tcp_server_t srv, mu_debug_t debug);
57 int mu_tcp_server_get_debug (mu_tcp_server_t srv, mu_debug_t *pdebug); 59 int mu_tcp_server_get_debug (mu_tcp_server_t srv, mu_debug_t *pdebug);
...@@ -67,6 +69,32 @@ int mu_tcp_server_shutdown (mu_tcp_server_t srv); ...@@ -67,6 +69,32 @@ int mu_tcp_server_shutdown (mu_tcp_server_t srv);
67 int mu_tcp_server_accept (mu_tcp_server_t srv, void *call_data); 69 int mu_tcp_server_accept (mu_tcp_server_t srv, void *call_data);
68 int mu_tcp_server_loop (mu_tcp_server_t srv, void *call_data); 70 int mu_tcp_server_loop (mu_tcp_server_t srv, void *call_data);
69 int mu_tcp_server_get_fd (mu_tcp_server_t srv); 71 int mu_tcp_server_get_fd (mu_tcp_server_t srv);
70 int mu_tcp_server_get_sockaddr (mu_tcp_server_t srv, struct sockaddr_in *s); 72 int mu_tcp_server_get_sockaddr (mu_tcp_server_t srv, struct sockaddr *s,
73 int *size);
74
75
76 /* m-server */
77 typedef int (*mu_m_server_conn_fp) (int, void *, time_t, int);
78
79 void mu_m_server_create (mu_m_server_t *psrv, const char *ident);
80 void mu_m_server_set_mode (mu_m_server_t srv, int mode);
81 void mu_m_server_set_conn (mu_m_server_t srv, mu_m_server_conn_fp f);
82 void mu_m_server_set_data (mu_m_server_t srv, void *data);
83 void mu_m_server_set_max_children (mu_m_server_t srv, size_t num);
84 int mu_m_server_set_pidfile (mu_m_server_t srv, const char *pidfile);
85 void mu_m_server_set_default_port (mu_m_server_t srv, int port);
86 void mu_m_server_set_timeout (mu_m_server_t srv, time_t t);
87 void mu_m_server_set_mode (mu_m_server_t srv, int mode);
88 void mu_m_server_set_sigset (mu_m_server_t srv, sigset_t *sigset);
89
90 int mu_m_server_mode (mu_m_server_t srv);
91 time_t mu_m_server_timeout (mu_m_server_t srv);
92 void mu_m_server_get_sigset (mu_m_server_t srv, sigset_t *sigset);
93
94 void mu_m_server_begin (mu_m_server_t msrv);
95 int mu_m_server_run (mu_m_server_t msrv);
96
97 void mu_m_server_cfg_init (void);
98
71 99
72 #endif 100 #endif
......
...@@ -108,6 +108,7 @@ typedef int mu_log_level_t; ...@@ -108,6 +108,7 @@ typedef int mu_log_level_t;
108 typedef struct _mu_acl *mu_acl_t; 108 typedef struct _mu_acl *mu_acl_t;
109 typedef struct _mu_server *mu_server_t; 109 typedef struct _mu_server *mu_server_t;
110 typedef struct _mu_tcp_server *mu_tcp_server_t; 110 typedef struct _mu_tcp_server *mu_tcp_server_t;
111 typedef struct _mu_m_server *mu_m_server_t;
111 112
112 #define MU_FOLDER_ATTRIBUTE_DIRECTORY 0x001 113 #define MU_FOLDER_ATTRIBUTE_DIRECTORY 0x001
113 #define MU_FOLDER_ATTRIBUTE_FILE 0x002 114 #define MU_FOLDER_ATTRIBUTE_FILE 0x002
......
...@@ -25,222 +25,7 @@ ...@@ -25,222 +25,7 @@
25 #include <signal.h> 25 #include <signal.h>
26 #include <mu_umaxtostr.h> 26 #include <mu_umaxtostr.h>
27 27
28 typedef union 28 static int lmtp_transcript;
29 {
30 struct sockaddr sa;
31 struct sockaddr_in s_in;
32 struct sockaddr_un s_un;
33 } all_addr_t;
34
35 static int
36 lmtp_open_internal (int *pfd, mu_url_t url, const char *urlstr)
37 {
38 int fd;
39 int rc;
40 int t = 1;
41 char buffer[64];
42 all_addr_t addr;
43 int addrsize;
44 mode_t saved_umask;
45
46 rc = mu_url_get_scheme (url, buffer, sizeof buffer, NULL);
47 if (rc)
48 {
49 mu_error (_("%s: cannot get scheme from URL: %s"),
50 urlstr, mu_strerror(rc));
51 return EX_CONFIG;
52 }
53
54 memset (&addr, 0, sizeof addr);
55 if (strcmp (buffer, "file") == 0 || strcmp (buffer, "socket") == 0)
56 {
57 size_t size;
58
59 rc = mu_url_get_path (url, NULL, 0, &size);
60 if (rc)
61 {
62 mu_error (_("%s: cannot get path: %s"), urlstr, mu_strerror(rc));
63 return EX_CONFIG;
64 }
65
66 if (size > sizeof addr.s_un.sun_path - 1)
67 {
68 mu_error (_("%s: file name too long"), urlstr);
69 return EX_TEMPFAIL;
70 }
71 mu_url_get_path (url, addr.s_un.sun_path, sizeof addr.s_un.sun_path,
72 NULL);
73
74 fd = socket (PF_UNIX, SOCK_STREAM, 0);
75 if (fd < 0)
76 {
77 mu_error ("socket: %s", mu_strerror (errno));
78 return EX_TEMPFAIL;
79 }
80
81 addr.s_un.sun_family = AF_UNIX;
82 addrsize = sizeof addr.s_un;
83
84 if (reuse_lmtp_address)
85 {
86 struct stat st;
87 if (stat (addr.s_un.sun_path, &st))
88 {
89 if (errno != ENOENT)
90 {
91 mu_error (_("file %s exists but cannot be stat'd"),
92 addr.s_un.sun_path);
93 return EX_TEMPFAIL;
94 }
95 }
96 else if (!S_ISSOCK (st.st_mode))
97 {
98 mu_error (_("file %s is not a socket"),
99 addr.s_un.sun_path);
100 return EX_TEMPFAIL;
101 }
102 else
103 unlink (addr.s_un.sun_path);
104 }
105
106 }
107 else if (strcmp (buffer, "tcp") == 0)
108 {
109 size_t size;
110 long n;
111 struct hostent *hp;
112 char *path = NULL;
113 short port = 0;
114
115 rc = mu_url_get_port (url, &n);
116 if (rc)
117 {
118 mu_error (_("%s: cannot get port: %s"), urlstr, mu_strerror(rc));
119 return EX_CONFIG;
120 }
121
122 if (n == 0 || (port = n) != n)
123 {
124 mu_error (_("Port out of range: %ld"), n);
125 return EX_CONFIG;
126 }
127
128 rc = mu_url_get_host (url, NULL, 0, &size);
129 if (rc)
130 {
131 mu_error (_("%s: cannot get host: %s"), urlstr, mu_strerror(rc));
132 return EX_CONFIG;
133 }
134 path = malloc (size + 1);
135 if (!path)
136 {
137 mu_error (_("Not enough memory"));
138 return EX_TEMPFAIL;
139 }
140 mu_url_get_host (url, path, size + 1, NULL);
141
142 fd = socket (PF_INET, SOCK_STREAM, 0);
143 if (fd < 0)
144 {
145 mu_error ("socket: %s", mu_strerror (errno));
146 return EX_TEMPFAIL;
147 }
148
149 addr.s_in.sin_family = AF_INET;
150 hp = gethostbyname (path);
151 if (hp)
152 {
153 char **ap;
154 int count = 0;
155
156 addr.s_in.sin_addr.s_addr = *(unsigned long*) hp->h_addr_list[0];
157
158 for (ap = hp->h_addr_list; *ap; ap++)
159 count++;
160 if (count > 1)
161 mu_error (_("warning: %s has several IP addresses, using %s"),
162 path, inet_ntoa (addr.s_in.sin_addr));
163 }
164 else if (inet_aton (path, &addr.s_in.sin_addr) == 0)
165 {
166 mu_error ("invalid IP address: %s", path);
167 return EX_TEMPFAIL;
168 }
169 addr.s_in.sin_port = htons (port);
170 addrsize = sizeof addr.s_in;
171
172 if (reuse_lmtp_address)
173 setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &t, sizeof(t));
174 }
175 else
176 {
177 mu_error (_("%s: invalid scheme"), urlstr);
178 return EX_CONFIG;
179 }
180
181 saved_umask = umask (0117);
182 if (bind (fd, &addr.sa, addrsize) == -1)
183 {
184 mu_error ("bind: %s", strerror (errno));
185 close (fd);
186 return EXIT_FAILURE;
187 }
188 umask (saved_umask);
189 *pfd = fd;
190 return 0;
191 }
192
193 int
194 lmtp_open (int *pfd, char *urlstr)
195 {
196 mu_url_t url = NULL;
197 int rc;
198
199 rc = mu_url_create (&url, urlstr);
200 if (rc)
201 {
202 mu_error (_("%s: cannot create URL: %s"),
203 urlstr, mu_strerror (rc));
204 return EX_CONFIG;
205 }
206 rc = mu_url_parse (url);
207 if (rc)
208 {
209 mu_error (_("%s: error parsing URL: %s"),
210 urlstr, mu_strerror(rc));
211 return EX_CONFIG;
212 }
213
214 rc = lmtp_open_internal (pfd, url, urlstr);
215 mu_url_destroy (&url);
216 return rc;
217 }
218
219 size_t children;
220 static int need_cleanup = 0;
221
222 void
223 process_cleanup ()
224 {
225 pid_t pid;
226 int status;
227
228 if (need_cleanup)
229 {
230 need_cleanup = 0;
231 while ( (pid = waitpid (-1, &status, WNOHANG)) > 0)
232 --children;
233 }
234 }
235
236 RETSIGTYPE
237 lmtp_sigchld (int signo MU_ARG_UNUSED)
238 {
239 need_cleanup = 1;
240 #ifndef HAVE_SIGACTION
241 signal (signo, lmtp_sigchld);
242 #endif
243 }
244 29
245 void 30 void
246 lmtp_reply (FILE *fp, char *code, char *enh, char *fmt, ...) 31 lmtp_reply (FILE *fp, char *code, char *enh, char *fmt, ...)
...@@ -252,7 +37,7 @@ lmtp_reply (FILE *fp, char *code, char *enh, char *fmt, ...) ...@@ -252,7 +37,7 @@ lmtp_reply (FILE *fp, char *code, char *enh, char *fmt, ...)
252 vasprintf (&str, fmt, ap); 37 vasprintf (&str, fmt, ap);
253 va_end (ap); 38 va_end (ap);
254 39
255 if (mu_gocs_daemon.transcript) 40 if (lmtp_transcript)
256 { 41 {
257 if (enh) 42 if (enh)
258 mu_diag_output (MU_DIAG_INFO, "LMTP reply: %s %s %s", code, enh, str); 43 mu_diag_output (MU_DIAG_INFO, "LMTP reply: %s %s %s", code, enh, str);
...@@ -697,8 +482,18 @@ getcmd (char *buf, char **sp) ...@@ -697,8 +482,18 @@ getcmd (char *buf, char **sp)
697 return cp; 482 return cp;
698 } 483 }
699 484
485 static char *
486 to_fgets (char *buf, size_t size, FILE *fp, unsigned int timeout)
487 {
488 char *p;
489 alarm (timeout);
490 p = fgets (buf, size, fp);
491 alarm (0);
492 return p;
493 }
494
700 int 495 int
701 lmtp_loop (FILE *in, FILE *out) 496 lmtp_loop (FILE *in, FILE *out, unsigned int timeout)
702 { 497 {
703 char buf[1024]; 498 char buf[1024];
704 enum lmtp_state state = state_init; 499 enum lmtp_state state = state_init;
...@@ -707,7 +502,7 @@ lmtp_loop (FILE *in, FILE *out) ...@@ -707,7 +502,7 @@ lmtp_loop (FILE *in, FILE *out)
707 setvbuf (out, NULL, _IOLBF, 0); 502 setvbuf (out, NULL, _IOLBF, 0);
708 503
709 lmtp_reply (out, "220", NULL, "At your service"); 504 lmtp_reply (out, "220", NULL, "At your service");
710 while (fgets (buf, sizeof buf, in)) 505 while (to_fgets (buf, sizeof buf, in, timeout))
711 { 506 {
712 if (state == state_data 507 if (state == state_data
713 && !(buf[0] == '.' 508 && !(buf[0] == '.'
...@@ -737,7 +532,7 @@ lmtp_loop (FILE *in, FILE *out) ...@@ -737,7 +532,7 @@ lmtp_loop (FILE *in, FILE *out)
737 532
738 trimnl (buf); 533 trimnl (buf);
739 534
740 if (mu_gocs_daemon.transcript) 535 if (lmtp_transcript)
741 mu_diag_output (MU_DIAG_INFO, "LMTP recieve: %s", buf); 536 mu_diag_output (MU_DIAG_INFO, "LMTP recieve: %s", buf);
742 537
743 if (next_state != state_none) 538 if (next_state != state_none)
...@@ -762,144 +557,15 @@ lmtp_loop (FILE *in, FILE *out) ...@@ -762,144 +557,15 @@ lmtp_loop (FILE *in, FILE *out)
762 } 557 }
763 558
764 int 559 int
765 check_connection (int fd, all_addr_t *addr, socklen_t addrlen) 560 lmtp_connection (int fd, void *data, time_t timeout, int transcript)
766 { 561 {
767 switch (addr->sa.sa_family) 562 /* FIXME: TCP wrappers */
768 { 563 lmtp_transcript = transcript;
769 case PF_UNIX: 564 lmtp_loop (fdopen (fd, "r"), fdopen (fd, "w"), timeout);
770 mu_diag_output (MU_DIAG_INFO, _("connect from socket"));
771 break;
772
773 case PF_INET:
774 if (maidag_acl)
775 {
776 mu_acl_result_t res;
777 int rc = mu_acl_check_sockaddr (maidag_acl, &addr->sa, addrlen,
778 &res);
779 if (rc)
780 {
781 mu_error (_("Access from %s blocked: cannot check ACLs: %s"),
782 inet_ntoa (addr->s_in.sin_addr), mu_strerror (rc));
783 return 1;
784 }
785 switch (res)
786 {
787 case mu_acl_result_undefined:
788 mu_diag_output (MU_DIAG_INFO,
789 _("%s: undefined ACL result; access allowed"),
790 inet_ntoa (addr->s_in.sin_addr));
791 break;
792
793 case mu_acl_result_accept:
794 break;
795
796 case mu_acl_result_deny:
797 mu_error (_("Access from %s blocked."),
798 inet_ntoa (addr->s_in.sin_addr));
799 return 1;
800 }
801 }
802
803 if (!mu_tcpwrapper_access (fd))
804 {
805 mu_error (_("Access from %s blocked by tcp wrappers."),
806 inet_ntoa (addr->s_in.sin_addr));
807 return 1;
808 }
809 }
810 return 0; 565 return 0;
811 } 566 }
812 567
813 int 568 int
814 lmtp_daemon (char *urlstr)
815 {
816 int rc;
817 int listenfd, connfd;
818 all_addr_t addr;
819 socklen_t addrlen;
820 pid_t pid;
821
822 if (mu_gocs_daemon.mode == MODE_DAEMON)
823 {
824 if (daemon (0, 0) < 0)
825 {
826 mu_error (_("Failed to become a daemon"));
827 return EX_UNAVAILABLE;
828 }
829 }
830
831 rc = lmtp_open (&listenfd, urlstr);
832 if (rc)
833 return rc;
834
835 if (listen (listenfd, 128) == -1)
836 {
837 mu_error ("listen: %s", strerror (errno));
838 close (listenfd);
839 return EX_UNAVAILABLE;
840 }
841
842 #ifdef HAVE_SIGACTION
843 {
844 struct sigaction act;
845 act.sa_handler = lmtp_sigchld;
846 sigemptyset (&act.sa_mask);
847 act.sa_flags = 0;
848 sigaction (SIGCHLD, &act, NULL);
849 }
850 #else
851 signal (SIGCHLD, lmtp_sigchld);
852 #endif
853
854 for (;;)
855 {
856 process_cleanup ();
857 if (children > mu_gocs_daemon.maxchildren)
858 {
859 mu_error (_("too many children (%lu)"),
860 (unsigned long) children);
861 pause ();
862 continue;
863 }
864 addrlen = sizeof addr;
865 connfd = accept (listenfd, (struct sockaddr *)&addr, &addrlen);
866 if (connfd == -1)
867 {
868 if (errno == EINTR)
869 continue;
870 mu_error ("accept: %s", strerror (errno));
871 continue;
872 /*exit (EXIT_FAILURE);*/
873 }
874
875 if (check_connection (connfd, &addr, addrlen))
876 {
877 close (connfd);
878 continue;
879 }
880
881 pid = fork ();
882 if (pid == -1)
883 mu_diag_output (MU_DIAG_ERROR, "fork: %s", strerror (errno));
884 else if (pid == 0) /* Child. */
885 {
886 int status;
887
888 close (listenfd);
889 status = lmtp_loop (fdopen (connfd, "r"), fdopen (connfd, "w"));
890 exit (status);
891 }
892 else
893 {
894 ++children;
895 }
896 close (connfd);
897 }
898 }
899
900 #define DEFAULT_URL "tcp://127.0.0.1:"
901
902 int
903 maidag_lmtp_server () 569 maidag_lmtp_server ()
904 { 570 {
905 struct group *gr = getgrnam (lmtp_group); 571 struct group *gr = getgrnam (lmtp_group);
...@@ -916,21 +582,16 @@ maidag_lmtp_server () ...@@ -916,21 +582,16 @@ maidag_lmtp_server ()
916 return EX_UNAVAILABLE; 582 return EX_UNAVAILABLE;
917 } 583 }
918 584
919 if (lmtp_url_string) 585 if (mu_m_server_mode (server) == MODE_DAEMON)
920 return lmtp_daemon (lmtp_url_string);
921 else if (mu_gocs_daemon.mode == MODE_INTERACTIVE)
922 return lmtp_loop (stdin, stdout);
923 else
924 {
925 const char *pstr = mu_umaxtostr (0, mu_gocs_daemon.port);
926 char *urls = malloc (sizeof (DEFAULT_URL) + strlen (pstr));
927 if (!urls)
928 { 586 {
929 mu_error (_("Not enough memory")); 587 int status;
930 return EX_TEMPFAIL; 588 mu_m_server_begin (server);
931 } 589 status = mu_m_server_run (server);
932 strcpy (urls, DEFAULT_URL); 590 mu_m_server_end (server);
933 strcat (urls, pstr); 591 mu_m_server_destroy (&server);
934 return lmtp_daemon (urls); 592 if (status)
593 return EX_CONFIG;
935 } 594 }
595 else
596 return lmtp_loop (stdin, stdout, 0);
936 } 597 }
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail 1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2007 Free Software Foundation, Inc. 2 Copyright (C) 2007, 2008 Free Software Foundation, Inc.
3 3
4 GNU Mailutils is free software; you can redistribute it and/or modify 4 GNU Mailutils is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by 5 it under the terms of the GNU General Public License as published by
...@@ -43,20 +43,11 @@ char *message_id_header; /* Use the value of this header as message ...@@ -43,20 +43,11 @@ char *message_id_header; /* Use the value of this header as message
43 identifier when logging Sieve actions */ 43 identifier when logging Sieve actions */
44 44
45 /* For LMTP mode */ 45 /* For LMTP mode */
46 mu_m_server_t server;
46 int lmtp_mode; 47 int lmtp_mode;
47 char *lmtp_url_string; 48 char *lmtp_url_string;
48 int reuse_lmtp_address = 1; 49 int reuse_lmtp_address = 1;
49 char *lmtp_group = "mail"; 50 char *lmtp_group = "mail";
50 mu_acl_t maidag_acl; /* ACLs for LMTP mode */
51
52 struct mu_gocs_daemon daemon_param = {
53 MODE_INTERACTIVE, /* Start in interactive (inetd) mode */
54 20, /* Default maximum number of children */
55 0, /* No standard port */
56 600, /* Idle timeout */
57 0, /* No transcript by default */
58 NULL /* No PID file by default */
59 };
60 51
61 const char *program_version = "maidag (" PACKAGE_STRING ")"; 52 const char *program_version = "maidag (" PACKAGE_STRING ")";
62 static char doc[] = 53 static char doc[] =
...@@ -74,9 +65,15 @@ static char args_doc[] = N_("[recipient...]"); ...@@ -74,9 +65,15 @@ static char args_doc[] = N_("[recipient...]");
74 #define STDERR_OPTION 256 65 #define STDERR_OPTION 256
75 #define MESSAGE_ID_HEADER_OPTION 257 66 #define MESSAGE_ID_HEADER_OPTION 257
76 #define LMTP_OPTION 258 67 #define LMTP_OPTION 258
68 #define FOREGROUND_OPTION 260
77 69
78 static struct argp_option options[] = 70 static struct argp_option options[] =
79 { 71 {
72 { "foreground", FOREGROUND_OPTION, 0, 0, N_("Remain in foreground."), 0 },
73 { "inetd", 'i', 0, 0, N_("Run in inetd mode"), 0 },
74 { "daemon", 'd', N_("NUMBER"), OPTION_ARG_OPTIONAL,
75 N_("Runs in daemon mode with a maximum of NUMBER children"), 0 },
76
80 { "from", 'f', N_("EMAIL"), 0, 77 { "from", 'f', N_("EMAIL"), 0,
81 N_("Specify the sender's name") }, 78 N_("Specify the sender's name") },
82 { NULL, 'r', NULL, OPTION_ALIAS, NULL }, 79 { NULL, 'r', NULL, OPTION_ALIAS, NULL },
...@@ -109,7 +106,6 @@ static struct argp argp = { ...@@ -109,7 +106,6 @@ static struct argp argp = {
109 }; 106 };
110 107
111 static const char *maidag_argp_capa[] = { 108 static const char *maidag_argp_capa[] = {
112 "daemon",
113 "auth", 109 "auth",
114 "common", 110 "common",
115 "debug", 111 "debug",
...@@ -174,6 +170,20 @@ parse_opt (int key, char *arg, struct argp_state *state) ...@@ -174,6 +170,20 @@ parse_opt (int key, char *arg, struct argp_state *state)
174 170
175 switch (key) 171 switch (key)
176 { 172 {
173 case 'd':
174 mu_argp_node_list_new (&lst, "mode", "daemon");
175 if (arg)
176 mu_argp_node_list_new (&lst, "max-children", arg);
177 break;
178
179 case 'i':
180 mu_argp_node_list_new (&lst, "mode", "inetd");
181 break;
182
183 case FOREGROUND_OPTION:
184 mu_argp_node_list_new (&lst, "foreground", "yes");
185 break;
186
177 case MESSAGE_ID_HEADER_OPTION: 187 case MESSAGE_ID_HEADER_OPTION:
178 mu_argp_node_list_new (&lst, "message-id-header", arg); 188 mu_argp_node_list_new (&lst, "message-id-header", arg);
179 break; 189 break;
...@@ -291,7 +301,8 @@ struct mu_cfg_param maidag_cfg_param[] = { ...@@ -291,7 +301,8 @@ struct mu_cfg_param maidag_cfg_param[] = {
291 N_("url") }, 301 N_("url") },
292 { "reuse-address", mu_cfg_bool, &reuse_lmtp_address, 0, NULL, 302 { "reuse-address", mu_cfg_bool, &reuse_lmtp_address, 0, NULL,
293 N_("Reuse existing address (LMTP mode). Default is \"yes\".") }, 303 N_("Reuse existing address (LMTP mode). Default is \"yes\".") },
294 { "acl", mu_cfg_section, }, 304 { ".server", mu_cfg_section, NULL, 0, NULL,
305 N_("LMTP server configuration.") },
295 TCP_WRAPPERS_CONFIG 306 TCP_WRAPPERS_CONFIG
296 { NULL } 307 { NULL }
297 }; 308 };
...@@ -458,15 +469,21 @@ main (int argc, char *argv[]) ...@@ -458,15 +469,21 @@ main (int argc, char *argv[])
458 469
459 mu_gocs_register ("sieve", mu_sieve_module_init); 470 mu_gocs_register ("sieve", mu_sieve_module_init);
460 471
461 mu_gocs_daemon = daemon_param;
462
463 mu_tcpwrapper_cfg_init (); 472 mu_tcpwrapper_cfg_init ();
464 mu_acl_cfg_init (); 473 mu_acl_cfg_init ();
474 mu_m_server_cfg_init ();
465 475
466 /* Parse command line */ 476 /* Parse command line */
467 mu_argp_init (program_version, NULL); 477 mu_argp_init (program_version, NULL);
478
479 mu_m_server_create (&server, "GNU maidag");
480 mu_m_server_set_conn (server, lmtp_connection);
481 mu_m_server_set_mode (server, MODE_INTERACTIVE);
482 mu_m_server_set_max_children (server, 20);
483 mu_m_server_set_timeout (server, 600);
484
468 if (mu_app_init (&argp, maidag_argp_capa, maidag_cfg_param, 485 if (mu_app_init (&argp, maidag_argp_capa, maidag_cfg_param,
469 argc, argv, 0, &arg_index, &maidag_acl)) 486 argc, argv, 0, &arg_index, server))
470 exit (EX_CONFIG); 487 exit (EX_CONFIG);
471 488
472 current_uid = getuid (); 489 current_uid = getuid ();
...@@ -481,12 +498,8 @@ main (int argc, char *argv[]) ...@@ -481,12 +498,8 @@ main (int argc, char *argv[])
481 openlog ("maidag", LOG_PID, log_facility); 498 openlog ("maidag", LOG_PID, log_facility);
482 mu_diag_get_debug (&debug); 499 mu_diag_get_debug (&debug);
483 mu_debug_set_print (debug, mu_diag_syslog_printer, NULL); 500 mu_debug_set_print (debug, mu_diag_syslog_printer, NULL);
484 /* FIXME: this should be done automatically by cfg */ 501
485 if (maidag_acl) 502 mu_debug_default_printer = mu_debug_syslog_printer;
486 {
487 mu_acl_get_debug (maidag_acl, &debug);
488 mu_debug_set_print (debug, mu_debug_syslog_printer, NULL);
489 }
490 } 503 }
491 504
492 argc -= arg_index; 505 argc -= arg_index;
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail 1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2007 Free Software Foundation, Inc. 2 Copyright (C) 2007, 2008 Free Software Foundation, Inc.
3 3
4 GNU Mailutils is free software; you can redistribute it and/or modify 4 GNU Mailutils is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by 5 it under the terms of the GNU General Public License as published by
...@@ -84,6 +84,7 @@ ...@@ -84,6 +84,7 @@
84 #include <mailutils/nls.h> 84 #include <mailutils/nls.h>
85 #include <mailutils/daemon.h> 85 #include <mailutils/daemon.h>
86 #include <mailutils/acl.h> 86 #include <mailutils/acl.h>
87 #include <mailutils/server.h>
87 88
88 #include <mu_dbm.h> 89 #include <mu_dbm.h>
89 #include <mu_asprintf.h> 90 #include <mu_asprintf.h>
...@@ -120,6 +121,7 @@ extern char *sender_address; ...@@ -120,6 +121,7 @@ extern char *sender_address;
120 extern char *progfile_pattern; 121 extern char *progfile_pattern;
121 extern char *sieve_pattern; 122 extern char *sieve_pattern;
122 123
124 extern mu_m_server_t server;
123 extern int lmtp_mode; 125 extern int lmtp_mode;
124 extern char *lmtp_url_string; 126 extern char *lmtp_url_string;
125 extern int reuse_lmtp_address; 127 extern int reuse_lmtp_address;
...@@ -131,6 +133,7 @@ int switch_user_id (struct mu_auth_data *auth, int user); ...@@ -131,6 +133,7 @@ int switch_user_id (struct mu_auth_data *auth, int user);
131 133
132 int maidag_stdio_delivery (int argc, char **argv); 134 int maidag_stdio_delivery (int argc, char **argv);
133 int maidag_lmtp_server (void); 135 int maidag_lmtp_server (void);
136 int lmtp_connection (int fd, void *data, time_t timeout, int transcript);
134 137
135 void mailer_err (char *fmt, ...); 138 void mailer_err (char *fmt, ...);
136 void notify_biff (mu_mailbox_t mbox, char *name, size_t size); 139 void notify_biff (mu_mailbox_t mbox, char *name, size_t size);
......
...@@ -82,6 +82,7 @@ libmailutils_la_SOURCES = \ ...@@ -82,6 +82,7 @@ libmailutils_la_SOURCES = \
82 message_stream.c\ 82 message_stream.c\
83 mime.c\ 83 mime.c\
84 monitor.c\ 84 monitor.c\
85 msrv.c\
85 mu_auth.c\ 86 mu_auth.c\
86 mu_umaxtostr.h\ 87 mu_umaxtostr.h\
87 mu_umaxtostr.c\ 88 mu_umaxtostr.c\
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail 1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2007 Free Software Foundation, Inc. 2 Copyright (C) 2007, 2008 Free Software Foundation, Inc.
3 3
4 This library is free software; you can redistribute it and/or 4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public 5 modify it under the terms of the GNU Lesser General Public
...@@ -307,16 +307,17 @@ mu_acl_string_to_action (const char *str, mu_acl_action_t *pres) ...@@ -307,16 +307,17 @@ mu_acl_string_to_action (const char *str, mu_acl_action_t *pres)
307 return rc; 307 return rc;
308 } 308 }
309 309
310 void 310 static void
311 debug_sockaddr (mu_debug_t dbg, mu_log_level_t lvl, struct sockaddr *sa) 311 debug_sockaddr (mu_debug_t dbg, mu_log_level_t lvl, struct sockaddr *sa)
312 { 312 {
313 switch (sa->sa_family) 313 switch (sa->sa_family)
314 { 314 {
315 case AF_INET: 315 case AF_INET:
316 { 316 {
317 struct sockaddr_in *s_in = (struct sockaddr_in *)sa; 317 struct sockaddr_in s_in = *(struct sockaddr_in *)sa;
318 s_in.sin_addr.s_addr = htonl (s_in.sin_addr.s_addr);
318 mu_debug_printf (dbg, lvl, "{AF_INET %s:%d}", 319 mu_debug_printf (dbg, lvl, "{AF_INET %s:%d}",
319 inet_ntoa (s_in->sin_addr), ntohs (s_in->sin_port)); 320 inet_ntoa (s_in.sin_addr), ntohs (s_in.sin_port));
320 break; 321 break;
321 } 322 }
322 323
...@@ -332,6 +333,77 @@ debug_sockaddr (mu_debug_t dbg, mu_log_level_t lvl, struct sockaddr *sa) ...@@ -332,6 +333,77 @@ debug_sockaddr (mu_debug_t dbg, mu_log_level_t lvl, struct sockaddr *sa)
332 } 333 }
333 } 334 }
334 335
336 size_t
337 mu_stpcpy (char **pbuf, size_t *psize, const char *src)
338 {
339 size_t slen = strlen (src);
340 if (pbuf == NULL || *pbuf == NULL)
341 return slen;
342 else
343 {
344 char *buf = *pbuf;
345 size_t size = *psize;
346 if (size > slen)
347 size = slen;
348 memcpy (buf, src, size);
349 *psize -= size;
350 *pbuf += size;
351 if (*psize)
352 **pbuf = 0;
353 else
354 (*pbuf)[-1] = 0;
355 return size;
356 }
357 }
358
359 void
360 mu_sockaddr_to_str (struct sockaddr *sa, int salen,
361 char *bufptr, size_t buflen,
362 size_t *plen)
363 {
364 char buf[UINTMAX_STRSIZE_BOUND]; /* FIXME: too much */
365 size_t len = 0;
366 switch (sa->sa_family)
367 {
368 case AF_INET:
369 {
370 struct sockaddr_in s_in = *(struct sockaddr_in *)sa;
371 len += mu_stpcpy (&bufptr, &buflen, inet_ntoa (s_in.sin_addr));
372 len += mu_stpcpy (&bufptr, &buflen, ":");
373 len += mu_stpcpy (&bufptr, &buflen, umaxtostr (ntohs (s_in.sin_port),
374 buf));
375 break;
376 }
377
378 case AF_UNIX:
379 {
380 struct sockaddr_un *s_un = (struct sockaddr_un *)sa;
381 len += mu_stpcpy (&bufptr, &buflen, "socket ");
382 len += mu_stpcpy (&bufptr, &buflen, s_un->sun_path);
383 break;
384 }
385
386 default:
387 len += mu_stpcpy (&bufptr, &buflen, "{Unsupported family: ");
388 len += mu_stpcpy (&bufptr, &buflen, umaxtostr (sa->sa_family, buf));
389 }
390 if (plen)
391 *plen = len + 1;
392 }
393
394 char *
395 mu_sockaddr_to_astr (struct sockaddr *sa, int salen)
396 {
397 size_t size;
398 char *p;
399
400 mu_sockaddr_to_str (sa, salen, NULL, 0, &size);
401 p = malloc (size);
402 if (p)
403 mu_sockaddr_to_str (sa, salen, p, size, NULL);
404 return p;
405 }
406
335 int 407 int
336 _acl_match (mu_debug_t debug, struct _mu_acl_entry *ent, struct sockaddr *sa) 408 _acl_match (mu_debug_t debug, struct _mu_acl_entry *ent, struct sockaddr *sa)
337 { 409 {
...@@ -348,6 +420,7 @@ _acl_match (mu_debug_t debug, struct _mu_acl_entry *ent, struct sockaddr *sa) ...@@ -348,6 +420,7 @@ _acl_match (mu_debug_t debug, struct _mu_acl_entry *ent, struct sockaddr *sa)
348 mu_debug_printf (debug, MU_DEBUG_TRACE0, " match "); 420 mu_debug_printf (debug, MU_DEBUG_TRACE0, " match ");
349 debug_sockaddr (debug, MU_DEBUG_TRACE0, ent->sa); 421 debug_sockaddr (debug, MU_DEBUG_TRACE0, ent->sa);
350 a.s_addr = ent->netmask; 422 a.s_addr = ent->netmask;
423 a.s_addr = htonl (a.s_addr);
351 mu_debug_printf (debug, MU_DEBUG_TRACE0, " netmask %s? ", inet_ntoa (a)); 424 mu_debug_printf (debug, MU_DEBUG_TRACE0, " netmask %s? ", inet_ntoa (a));
352 } 425 }
353 426
......
1 /* cfg_driver.c -- Main driver for Mailutils configuration files 1 /* cfg_driver.c -- Main driver for Mailutils configuration files
2 Copyright (C) 2007 Free Software Foundation, Inc. 2 Copyright (C) 2007, 2008 Free Software Foundation, Inc.
3 3
4 GNU Mailutils is free software; you can redistribute it and/or 4 GNU Mailutils is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License as 5 modify it under the terms of the GNU General Public License as
...@@ -163,6 +163,7 @@ dup_container (struct mu_cfg_cont **pcont) ...@@ -163,6 +163,7 @@ dup_container (struct mu_cfg_cont **pcont)
163 newcont->v.section.label = oldcont->v.section.label; 163 newcont->v.section.label = oldcont->v.section.label;
164 newcont->v.section.parser = oldcont->v.section.parser; 164 newcont->v.section.parser = oldcont->v.section.parser;
165 newcont->v.section.target = oldcont->v.section.target; 165 newcont->v.section.target = oldcont->v.section.target;
166 newcont->v.section.offset = oldcont->v.section.offset;
166 newcont->v.section.docstring = oldcont->v.section.docstring; 167 newcont->v.section.docstring = oldcont->v.section.docstring;
167 newcont->v.section.children = NULL; 168 newcont->v.section.children = NULL;
168 mu_list_do (oldcont->v.section.children, _dup_cont_action, &dd); 169 mu_list_do (oldcont->v.section.children, _dup_cont_action, &dd);
...@@ -259,9 +260,42 @@ mu_cfg_section_add_params (struct mu_cfg_section *sect, ...@@ -259,9 +260,42 @@ mu_cfg_section_add_params (struct mu_cfg_section *sect,
259 param->ident); 260 param->ident);
260 abort (); 261 abort ();
261 } 262 }
263 if (param->ident[0] == '.')
264 {
265 mu_iterator_t itr;
266 mu_list_get_iterator (container->v.section.children, &itr);
267 for (mu_iterator_first (itr);
268 !mu_iterator_is_done (itr);
269 mu_iterator_next (itr))
270 {
271 struct mu_cfg_cont *c;
272 mu_iterator_current (itr, (void**)&c);
273 mu_config_clone_container (c);
274 if (mu_refcount_value (c->refcount) > 1)
275 dup_container (&c);
276 switch (c->type)
277 {
278 case mu_cfg_cont_section:
279 c->v.section.offset += param->offset;
280 break;
281
282 case mu_cfg_cont_param:
283 container->v.param.offset += param->offset;
284 break;
285 }
286 mu_cfg_section_add_container (sect, c);
287 }
288 mu_iterator_destroy (&itr);
289 continue;
290 }
291 else
292 {
262 mu_config_clone_container (container); 293 mu_config_clone_container (container);
294 if (mu_refcount_value (container->refcount) > 1)
295 dup_container (&container);
263 container->v.section.offset = param->offset; 296 container->v.section.offset = param->offset;
264 } 297 }
298 }
265 else 299 else
266 { 300 {
267 rc = mu_config_create_container (&container, mu_cfg_cont_param); 301 rc = mu_config_create_container (&container, mu_cfg_cont_param);
......
1 /* cfg_lexer.c -- default lexer for Mailutils configuration files 1 /* cfg_lexer.c -- default lexer for Mailutils configuration files
2 Copyright (C) 2007 Free Software Foundation, Inc. 2 Copyright (C) 2007, 2008 Free Software Foundation, Inc.
3 3
4 GNU Mailutils is free software; you can redistribute it and/or 4 GNU Mailutils is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License as 5 modify it under the terms of the GNU General Public License as
...@@ -118,7 +118,7 @@ static int ...@@ -118,7 +118,7 @@ static int
118 isword (int c) 118 isword (int c)
119 { 119 {
120 if (mu_cfg_tie_in) 120 if (mu_cfg_tie_in)
121 return c && c != ';'; 121 return c && c != ';' && c != '{';
122 122
123 return isalnum (c) || c == '_' || c == '-' || c == '.'; 123 return isalnum (c) || c == '_' || c == '-' || c == '.';
124 } 124 }
...@@ -137,6 +137,22 @@ copy_alpha (struct lexer_data *p) ...@@ -137,6 +137,22 @@ copy_alpha (struct lexer_data *p)
137 return cbuf_finish (p); 137 return cbuf_finish (p);
138 } 138 }
139 139
140 static char *
141 copy_to (struct lexer_data *p, const char *delim)
142 {
143 while (*p->curp)
144 {
145 if (strchr (delim, *p->curp))
146 break;
147 if (*p->curp == '\n')
148 mu_cfg_locus.line++;
149 cbuf_1grow (p, *p->curp);
150 p->curp++;
151 }
152 cbuf_1grow (p, 0);
153 return cbuf_finish (p);
154 }
155
140 static int 156 static int
141 continuation_line_p (struct lexer_data *p, int quote) 157 continuation_line_p (struct lexer_data *p, int quote)
142 { 158 {
...@@ -210,6 +226,15 @@ copy_string (struct lexer_data *p) ...@@ -210,6 +226,15 @@ copy_string (struct lexer_data *p)
210 } \ 226 } \
211 while (0) 227 while (0)
212 228
229 static void
230 rtrim (char *arg)
231 {
232 int len = strlen (arg);
233 while (len > 0 && strchr (" \t\n\r", arg[len-1]))
234 len--;
235 arg[len] = 0;
236 }
237
213 int 238 int
214 default_lexer (void *dp, mu_debug_t dbg) 239 default_lexer (void *dp, mu_debug_t dbg)
215 { 240 {
...@@ -311,6 +336,7 @@ again: ...@@ -311,6 +336,7 @@ again:
311 336
312 tag = copy_alpha (p); 337 tag = copy_alpha (p);
313 skipws (p); 338 skipws (p);
339
314 if (*p->curp == '"') 340 if (*p->curp == '"')
315 { 341 {
316 mu_cfg_yylval.string = tag; 342 mu_cfg_yylval.string = tag;
...@@ -321,8 +347,8 @@ again: ...@@ -321,8 +347,8 @@ again:
321 save_start = p->curp; 347 save_start = p->curp;
322 if (*p->curp != '{') 348 if (*p->curp != '{')
323 { 349 {
324 label = copy_alpha (p); 350 label = copy_to (p, ";{");
325 skipws (p); 351 rtrim (label);
326 } 352 }
327 else 353 else
328 label = NULL; 354 label = NULL;
......
1 %{ 1 %{
2 /* cfg_parser.y -- general-purpose configuration file parser 2 /* cfg_parser.y -- general-purpose configuration file parser
3 Copyright (C) 2007 Free Software Foundation, Inc. 3 Copyright (C) 2007, 2008 Free Software Foundation, Inc.
4 4
5 GNU Mailutils is free software; you can redistribute it and/or 5 GNU Mailutils is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License as 6 modify it under the terms of the GNU General Public License as
...@@ -260,8 +260,17 @@ mu_cfg_parse (mu_cfg_tree_t **ptree, ...@@ -260,8 +260,17 @@ mu_cfg_parse (mu_cfg_tree_t **ptree,
260 _mu_cfg_debug = debug; 260 _mu_cfg_debug = debug;
261 else 261 else
262 { 262 {
263 mu_log_level_t level;
264
263 mu_debug_create (&_mu_cfg_debug, NULL); 265 mu_debug_create (&_mu_cfg_debug, NULL);
264 mu_debug_set_print (_mu_cfg_debug, _cfg_default_printer, NULL); 266 mu_debug_set_print (_mu_cfg_debug, _cfg_default_printer, NULL);
267 level = mu_global_debug_level ("config");
268 if (level)
269 {
270 mu_debug_set_level (_mu_cfg_debug, level);
271 if (level & MU_DEBUG_LEVEL_MASK (MU_DEBUG_TRACE7))
272 yydebug = 1;
273 }
265 } 274 }
266 _mu_cfg_alloc = palloc ? palloc : malloc; 275 _mu_cfg_alloc = palloc ? palloc : malloc;
267 _mu_cfg_free = pfree ? pfree : free; 276 _mu_cfg_free = pfree ? pfree : free;
...@@ -1006,14 +1015,20 @@ _scan_tree_helper (const mu_cfg_node_t *node, void *data) ...@@ -1006,14 +1015,20 @@ _scan_tree_helper (const mu_cfg_node_t *node, void *data)
1006 sec->target = (char*)sdata->list->sec->target + sec->offset; 1015 sec->target = (char*)sdata->list->sec->target + sec->offset;
1007 else if (sdata->target) 1016 else if (sdata->target)
1008 sec->target = (char*)sdata->target + sec->offset; 1017 sec->target = (char*)sdata->target + sec->offset;
1009 if (sec->parser && 1018 if (sec->parser)
1010 sec->parser (mu_cfg_section_start, node, 1019 {
1020 mu_debug_set_locus (sdata->tree->debug,
1021 node->locus.file ?
1022 node->locus.file : _("unknown file"),
1023 node->locus.line);
1024 if (sec->parser (mu_cfg_section_start, node,
1011 sec->label, &sec->target, 1025 sec->label, &sec->target,
1012 sdata->call_data, sdata->tree)) 1026 sdata->call_data, sdata->tree))
1013 { 1027 {
1014 sdata->error++; 1028 sdata->error++;
1015 return MU_CFG_ITER_SKIP; 1029 return MU_CFG_ITER_SKIP;
1016 } 1030 }
1031 }
1017 push_section(sdata, sec); 1032 push_section(sdata, sec);
1018 break; 1033 break;
1019 1034
...@@ -1059,15 +1074,26 @@ int ...@@ -1059,15 +1074,26 @@ int
1059 mu_cfg_scan_tree (mu_cfg_tree_t *tree, struct mu_cfg_section *sections, 1074 mu_cfg_scan_tree (mu_cfg_tree_t *tree, struct mu_cfg_section *sections,
1060 void *target, void *data) 1075 void *target, void *data)
1061 { 1076 {
1077 mu_debug_t debug = NULL;
1062 struct scan_tree_data dat; 1078 struct scan_tree_data dat;
1063 dat.tree = tree; 1079 dat.tree = tree;
1064 dat.list = NULL; 1080 dat.list = NULL;
1065 dat.error = 0; 1081 dat.error = 0;
1066 dat.call_data = data; 1082 dat.call_data = data;
1067 dat.target = target; 1083 dat.target = target;
1084 if (!tree->debug)
1085 {
1086 mu_diag_get_debug (&debug);
1087 tree->debug = debug;
1088 }
1068 if (push_section (&dat, sections)) 1089 if (push_section (&dat, sections))
1069 return 1; 1090 return 1;
1070 mu_cfg_preorder (tree->node, _scan_tree_helper, _scan_tree_end_helper, &dat); 1091 mu_cfg_preorder (tree->node, _scan_tree_helper, _scan_tree_end_helper, &dat);
1092 if (debug)
1093 {
1094 mu_debug_set_locus (debug, NULL, 0);
1095 tree->debug = NULL;
1096 }
1071 pop_section (&dat); 1097 pop_section (&dat);
1072 return dat.error; 1098 return dat.error;
1073 } 1099 }
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail 1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2004, 2005, 2007 Free Software Foundation, Inc. 2 Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
3 3
4 This library is free software; you can redistribute it and/or 4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public 5 modify it under the terms of the GNU Lesser General Public
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
29 #include <string.h> 29 #include <string.h>
30 30
31 #include <mailutils/daemon.h> 31 #include <mailutils/daemon.h>
32 #include <mailutils/errno.h>
32 #include <mu_umaxtostr.h> 33 #include <mu_umaxtostr.h>
33 34
34 static char *pidfile; 35 static char *pidfile;
...@@ -42,7 +43,7 @@ mu_daemon_create_pidfile (const char *filename) ...@@ -42,7 +43,7 @@ mu_daemon_create_pidfile (const char *filename)
42 43
43 if (filename[0] != '/') 44 if (filename[0] != '/')
44 { 45 {
45 return 1; /* failure */ 46 return EINVAL; /* failure */
46 } 47 }
47 48
48 if (pidfile) 49 if (pidfile)
...@@ -55,7 +56,7 @@ mu_daemon_create_pidfile (const char *filename) ...@@ -55,7 +56,7 @@ mu_daemon_create_pidfile (const char *filename)
55 if ((fd = open (pidfile, O_WRONLY | O_CREAT 56 if ((fd = open (pidfile, O_WRONLY | O_CREAT
56 | O_TRUNC | O_EXCL, 0644)) == -1) 57 | O_TRUNC | O_EXCL, 0644)) == -1)
57 { 58 {
58 return 2; /* failure */ 59 return errno; /* failure */
59 } 60 }
60 61
61 pid_string = mu_umaxtostr (0, current_pid); 62 pid_string = mu_umaxtostr (0, current_pid);
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail 1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 1999, 2000, 2001, 2004, 2005, 2 Copyright (C) 1999, 2000, 2001, 2004, 2005,
3 2007 Free Software Foundation, Inc. 3 2007, 2008 Free Software Foundation, Inc.
4 4
5 This library is free software; you can redistribute it and/or 5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public 6 modify it under the terms of the GNU Lesser General Public
...@@ -41,7 +41,7 @@ mu_debug_create (mu_debug_t *pdebug, void *owner) ...@@ -41,7 +41,7 @@ mu_debug_create (mu_debug_t *pdebug, void *owner)
41 debug = calloc (sizeof (*debug), 1); 41 debug = calloc (sizeof (*debug), 1);
42 if (debug == NULL) 42 if (debug == NULL)
43 return ENOMEM; 43 return ENOMEM;
44 debug->printer = mu_debug_default_printer; 44 debug->printer = NULL;
45 debug->owner = owner; 45 debug->owner = owner;
46 *pdebug = debug; 46 *pdebug = debug;
47 return 0; 47 return 0;
...@@ -146,10 +146,13 @@ int ...@@ -146,10 +146,13 @@ int
146 mu_debug_vprintf (mu_debug_t debug, mu_log_level_t level, 146 mu_debug_vprintf (mu_debug_t debug, mu_log_level_t level,
147 const char *format, va_list ap) 147 const char *format, va_list ap)
148 { 148 {
149 mu_debug_printer_fp printer;
150
149 if (debug == NULL || format == NULL) 151 if (debug == NULL || format == NULL)
150 return EINVAL; 152 return EINVAL;
151 153
152 if (debug->printer) 154 printer = debug->printer ? debug->printer : mu_debug_default_printer;
155 if (printer)
153 { 156 {
154 mu_off_t len; 157 mu_off_t len;
155 mu_transport_t tbuf; 158 mu_transport_t tbuf;
...@@ -186,7 +189,7 @@ mu_debug_vprintf (mu_debug_t debug, mu_log_level_t level, ...@@ -186,7 +189,7 @@ mu_debug_vprintf (mu_debug_t debug, mu_log_level_t level,
186 { 189 {
187 int c = *++p; 190 int c = *++p;
188 *p = 0; 191 *p = 0;
189 debug->printer (debug->data, level, ptr); 192 printer (debug->data, level, ptr);
190 *p = c; 193 *p = c;
191 ptr = p; 194 ptr = p;
192 nseg++; 195 nseg++;
...@@ -252,7 +255,7 @@ mu_debug_check_level (mu_debug_t debug, mu_log_level_t level) ...@@ -252,7 +255,7 @@ mu_debug_check_level (mu_debug_t debug, mu_log_level_t level)
252 { 255 {
253 if (!debug) 256 if (!debug)
254 return 0; 257 return 0;
255 return debug->level & level; 258 return debug->level & MU_DEBUG_LEVEL_MASK (level);
256 } 259 }
257 260
258 int 261 int
......
...@@ -90,7 +90,7 @@ mu_folder_create_from_record (mu_folder_t *pfolder, const char *name, ...@@ -90,7 +90,7 @@ mu_folder_create_from_record (mu_folder_t *pfolder, const char *name,
90 status = mu_url_parse (url); 90 status = mu_url_parse (url);
91 if (status) 91 if (status)
92 { 92 {
93 mu_url_destroy (url); 93 mu_url_destroy (&url);
94 return status; 94 return status;
95 } 95 }
96 mu_record_get_url (record, &u_init); 96 mu_record_get_url (record, &u_init);
...@@ -99,7 +99,7 @@ mu_folder_create_from_record (mu_folder_t *pfolder, const char *name, ...@@ -99,7 +99,7 @@ mu_folder_create_from_record (mu_folder_t *pfolder, const char *name,
99 status = u_init (url); 99 status = u_init (url);
100 if (status) 100 if (status)
101 { 101 {
102 mu_url_destroy (url); 102 mu_url_destroy (&url);
103 return status; 103 return status;
104 } 104 }
105 } 105 }
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2008 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 #ifdef HAVE_CONFIG_H
19 # include <config.h>
20 #endif
21 #include <sys/types.h>
22 #include <sys/wait.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <unistd.h>
26 #include <syslog.h>
27 #include <netdb.h>
28 #include <sys/socket.h>
29 #include <sys/un.h>
30 #include <sys/stat.h>
31 #include <ctype.h>
32 #include <mailutils/server.h>
33 #include <mailutils/error.h>
34 #include <mailutils/errno.h>
35 #include <mailutils/cfg.h>
36 #include <mailutils/nls.h>
37 #include <mailutils/daemon.h>
38 #include <mailutils/acl.h>
39
40 typedef RETSIGTYPE (*mu_sig_handler_t) (int);
41
42 static mu_sig_handler_t
43 set_signal (int sig, mu_sig_handler_t handler)
44 {
45 #ifdef HAVE_SIGACTION
46 {
47 struct sigaction act, oldact;
48 act.sa_handler = handler;
49 sigemptyset (&act.sa_mask);
50 act.sa_flags = 0;
51 sigaction (sig, &act, &oldact);
52 return oldact.sa_handler;
53 }
54 #else
55 return signal (sig, handler);
56 #endif
57 }
58
59 #ifndef NSIG
60 # define NSIG 64
61 #endif
62
63 struct _mu_m_server
64 {
65 char *ident;
66 mu_server_t server;
67 mu_list_t srvlist;
68 mu_m_server_conn_fp conn;
69 void *data;
70 int mode;
71 int foreground;
72 size_t max_children;
73 char *pidfile;
74 unsigned short defport;
75 time_t timeout;
76 mu_acl_t acl;
77
78 sigset_t sigmask;
79 mu_sig_handler_t sigtab[NSIG];
80 };
81
82 static int need_cleanup = 0;
83 static int stop = 0;
84 static size_t children;
85
86 static int
87 mu_m_server_idle (void *server_data MU_ARG_UNUSED)
88 {
89 pid_t pid;
90 int status;
91
92 if (need_cleanup)
93 {
94 need_cleanup = 0;
95 while ( (pid = waitpid (-1, &status, WNOHANG)) > 0)
96 {
97 --children;
98 if (WIFEXITED (status))
99 {
100 int prio = MU_DIAG_INFO;
101
102 status = WEXITSTATUS (status);
103 if (status == 0)
104 prio = MU_DIAG_DEBUG;
105 mu_diag_output (prio, "process %lu finished with code %d",
106 (unsigned long) pid,
107 status);
108 }
109 else if (WIFSIGNALED (status))
110 mu_diag_output (MU_DIAG_ERR, "process %lu terminated on signal %d",
111 (unsigned long) pid,
112 WTERMSIG (status));
113 else
114 mu_diag_output (MU_DIAG_ERR,
115 "process %lu terminated (cause unknown)",
116 (unsigned long) pid);
117 }
118 }
119 return stop;
120 }
121
122 static RETSIGTYPE
123 m_srv_signal (int signo)
124 {
125 switch (signo)
126 {
127 case SIGCHLD:
128 need_cleanup = 1;
129 break;
130
131 default:
132 stop = 1;
133 break;
134 }
135 #ifndef HAVE_SIGACTION
136 signal (signo, m_srv_sigchld);
137 #endif
138 }
139
140 void
141 mu_m_server_create (mu_m_server_t *psrv, const char *ident)
142 {
143 mu_m_server_t srv = calloc (1, sizeof *srv);
144 if (!srv)
145 {
146 mu_error ("%s", mu_strerror (ENOMEM));
147 exit (1);
148 }
149 if (ident)
150 {
151 srv->ident = strdup (ident);
152 if (!srv->ident)
153 {
154 mu_error ("%s", mu_strerror (ENOMEM));
155 exit (1);
156 }
157 }
158 MU_ASSERT (mu_server_create (&srv->server));
159 mu_server_set_idle (srv->server, mu_m_server_idle);
160 sigemptyset (&srv->sigmask);
161 sigaddset (&srv->sigmask, SIGCHLD);
162 sigaddset (&srv->sigmask, SIGINT);
163 sigaddset (&srv->sigmask, SIGTERM);
164 sigaddset (&srv->sigmask, SIGQUIT);
165 sigaddset (&srv->sigmask, SIGHUP);
166 *psrv = srv;
167 }
168
169 void
170 mu_m_server_set_sigset (mu_m_server_t srv, sigset_t *sigset)
171 {
172 srv->sigmask = *sigset;
173 sigaddset (&srv->sigmask, SIGCHLD);
174 }
175
176 void
177 mu_m_server_get_sigset (mu_m_server_t srv, sigset_t *sigset)
178 {
179 *sigset = srv->sigmask;
180 }
181
182 void
183 mu_m_server_set_mode (mu_m_server_t srv, int mode)
184 {
185 srv->mode = mode;
186 }
187
188 void
189 mu_m_server_set_conn (mu_m_server_t srv, mu_m_server_conn_fp conn)
190 {
191 srv->conn = conn;
192 }
193
194 void
195 mu_m_server_set_data (mu_m_server_t srv, void *data)
196 {
197 srv->data = data;
198 }
199
200 void
201 mu_m_server_set_max_children (mu_m_server_t srv, size_t num)
202 {
203 srv->max_children = num;
204 }
205
206 int
207 mu_m_server_set_pidfile (mu_m_server_t srv, const char *pidfile)
208 {
209 free (srv->pidfile);
210 srv->pidfile = strdup (pidfile);
211 return srv->pidfile ? 0 : errno;
212 }
213
214 void
215 mu_m_server_set_default_port (mu_m_server_t srv, int port)
216 {
217 srv->defport = port;
218 }
219
220 void
221 mu_m_server_set_timeout (mu_m_server_t srv, time_t t)
222 {
223 srv->timeout = t;
224 }
225
226 int
227 mu_m_server_mode (mu_m_server_t srv)
228 {
229 return srv->mode;
230 }
231
232 time_t
233 mu_m_server_timeout (mu_m_server_t srv)
234 {
235 return srv->timeout;
236 }
237
238 struct m_srv_config
239 {
240 mu_m_server_t msrv;
241 mu_tcp_server_t tcpsrv;
242 mu_acl_t acl;
243 int single_process;
244 int transcript;
245 time_t timeout;
246 };
247
248 void
249 m_srv_config_free (void *data)
250 {
251 struct m_srv_config *pconf = data;
252 /* FIXME */
253 free (pconf);
254 }
255
256 static int m_srv_conn (int fd, struct sockaddr *sa, int salen,
257 void *server_data, void *call_data,
258 mu_tcp_server_t srv);
259
260 static struct m_srv_config *
261 add_server (mu_m_server_t msrv, struct sockaddr *s, int slen)
262 {
263 mu_tcp_server_t tcpsrv;
264 struct m_srv_config *pconf;
265
266 MU_ASSERT (mu_tcp_server_create (&tcpsrv, s, slen));
267 MU_ASSERT (mu_tcp_server_set_conn (tcpsrv, m_srv_conn));
268 pconf = calloc (1, sizeof (*pconf));
269 if (!pconf)
270 {
271 mu_error ("%s", mu_strerror (ENOMEM));
272 exit (1);
273 }
274 pconf->msrv = msrv;
275 pconf->tcpsrv = tcpsrv;
276 pconf->single_process = 0;
277 pconf->timeout = msrv->timeout;
278 MU_ASSERT (mu_tcp_server_set_data (tcpsrv, pconf, m_srv_config_free));
279 if (!msrv->srvlist)
280 MU_ASSERT (mu_list_create (&msrv->srvlist));
281 MU_ASSERT (mu_list_append (msrv->srvlist, tcpsrv));
282 return pconf;
283 }
284
285 void
286 mu_m_server_configured_count (mu_m_server_t msrv, size_t count)
287 {
288 mu_list_count (msrv->srvlist, &count);
289 }
290
291 void
292 mu_m_server_begin (mu_m_server_t msrv)
293 {
294 int i, rc;
295 size_t count = 0;
296
297 mu_list_count (msrv->srvlist, &count);
298 if (count == 0 && msrv->defport)
299 {
300 /* Add default server */
301 struct sockaddr_in s;
302 s.sin_addr.s_addr = htonl (INADDR_ANY);
303 s.sin_port = htons (msrv->defport);
304 add_server (msrv, (struct sockaddr *)&s, sizeof s);
305 }
306
307 if (!msrv->foreground)
308 {
309 /* Become a daemon. Take care to close inherited fds and to hold
310 first three one, in, out, err */
311 if (daemon (0, 0) < 0)
312 {
313 mu_error (_("Failed to become a daemon: %s"), mu_strerror (errno));
314 exit (EXIT_FAILURE);
315 }
316 }
317
318 if (msrv->pidfile)
319 switch (rc = mu_daemon_create_pidfile (msrv->pidfile))
320 {
321 case EINVAL:
322 mu_error (_("%s: Invalid name for a pidfile"), msrv->pidfile);
323 break;
324
325 default:
326 mu_error (_("cannot create pidfile `%s': %s"), msrv->pidfile,
327 mu_strerror (rc));
328 }
329
330 for (i = 0; i < NSIG; i++)
331 if (sigismember (&msrv->sigmask, i))
332 msrv->sigtab[i] = set_signal (i, m_srv_signal);
333 }
334
335 void
336 mu_m_server_end (mu_m_server_t msrv)
337 {
338 int i;
339
340 for (i = 0; i < NSIG; i++)
341 if (sigismember (&msrv->sigmask, i))
342 set_signal (i, msrv->sigtab[i]);
343 }
344
345 void
346 mu_m_server_destroy (mu_m_server_t *pmsrv)
347 {
348 mu_m_server_t msrv = *pmsrv;
349 mu_server_destroy (&msrv->server);
350 /* FIXME: Send processes the TERM signal */
351 free (msrv->ident);
352 free (msrv);
353 *pmsrv = NULL;
354 }
355
356 static int
357 tcp_conn_handler (int fd, void *conn_data, void *server_data)
358 {
359 mu_tcp_server_t tcpsrv = (mu_tcp_server_t) conn_data;
360 int rc = mu_tcp_server_accept (tcpsrv, server_data);
361 if (rc && rc != EINTR)
362 {
363 mu_tcp_server_shutdown (tcpsrv);
364 return MU_SERVER_CLOSE_CONN;
365 }
366 return stop ? MU_SERVER_SHUTDOWN : MU_SERVER_SUCCESS;
367 }
368
369 static void
370 tcp_conn_free (void *conn_data, void *server_data)
371 {
372 mu_tcp_server_t tcpsrv = (mu_tcp_server_t) conn_data;
373 mu_tcp_server_destroy (&tcpsrv);
374 }
375
376 static int
377 _open_conn (void *item, void *data)
378 {
379 union
380 {
381 struct sockaddr sa;
382 char pad[512];
383 }
384 addr;
385 int addrlen = sizeof addr;
386 char *p;
387 mu_tcp_server_t tcpsrv = item;
388 mu_m_server_t msrv = data;
389 int rc = mu_tcp_server_open (tcpsrv);
390 if (rc)
391 {
392 mu_tcp_server_get_sockaddr (tcpsrv, &addr.sa, &addrlen);
393 p = mu_sockaddr_to_astr (&addr.sa, addrlen);
394 mu_error (_("Cannot open connection on %s: %s"), p, mu_strerror (rc));
395 free (p);
396 return 0;
397 }
398 rc = mu_server_add_connection (msrv->server,
399 mu_tcp_server_get_fd (tcpsrv),
400 tcpsrv,
401 tcp_conn_handler, tcp_conn_free);
402 if (rc)
403 {
404 mu_tcp_server_get_sockaddr (tcpsrv, &addr.sa, &addrlen);
405 p = mu_sockaddr_to_astr (&addr.sa, addrlen);
406 mu_error (_("Cannot add connection %s: %s"), p, mu_strerror (rc));
407 free (p);
408 mu_tcp_server_shutdown (tcpsrv);
409 mu_tcp_server_destroy (&tcpsrv);
410 }
411 return 0;
412 }
413
414 int
415 mu_m_server_run (mu_m_server_t msrv)
416 {
417 int rc;
418 size_t count;
419 mode_t saved_umask = umask (0117);
420 mu_list_do (msrv->srvlist, _open_conn, msrv);
421 umask (saved_umask);
422 mu_list_destroy (&msrv->srvlist);
423 MU_ASSERT (mu_server_count (msrv->server, &count));
424 if (count == 0)
425 {
426 mu_error (_("No servers configured: exiting"));
427 exit (1);
428 }
429 if (msrv->ident)
430 mu_diag_output (MU_DIAG_INFO, _("%s started"), msrv->ident);
431 rc = mu_server_run (msrv->server);
432 if (msrv->ident)
433 mu_diag_output (MU_DIAG_INFO, _("%s terminated"), msrv->ident);
434 return rc;
435 }
436
437
438
439 static int
440 check_global_acl (mu_m_server_t msrv, struct sockaddr *s, int salen)
441 {
442 if (msrv->acl)
443 {
444 mu_acl_result_t res;
445 int rc = mu_acl_check_sockaddr (msrv->acl, s, salen, &res);
446 if (rc)
447 {
448 char *p = mu_sockaddr_to_astr (s, salen);
449 mu_error (_("Access from %s blocked: cannot check ACLs: %s"),
450 p, mu_strerror (rc));
451 free (p);
452 return 1;
453 }
454 switch (res)
455 {
456 case mu_acl_result_undefined:
457 {
458 char *p = mu_sockaddr_to_astr (s, salen);
459 mu_diag_output (MU_DIAG_INFO,
460 _("%s: undefined ACL result; access allowed"),
461 p);
462 free (p);
463 }
464 break;
465
466 case mu_acl_result_accept:
467 break;
468
469 case mu_acl_result_deny:
470 {
471 char *p = mu_sockaddr_to_astr (s, salen);
472 mu_error (_("Access from %s blocked."), p);
473 free (p);
474 return 1;
475 }
476 }
477 }
478 return 0;
479 }
480
481 int
482 m_srv_conn (int fd, struct sockaddr *sa, int salen,
483 void *server_data, void *call_data,
484 mu_tcp_server_t srv)
485 {
486 int status;
487 struct m_srv_config *pconf = server_data;
488
489 if (check_global_acl (pconf->msrv, sa, salen))
490 return 0;
491
492 if (!pconf->single_process)
493 {
494 pid_t pid;
495
496 if (mu_m_server_idle (server_data))
497 return MU_SERVER_SHUTDOWN;
498 if (children >= pconf->msrv->max_children)
499 {
500 mu_diag_output (MU_DIAG_ERROR, _("too many children (%lu)"),
501 (unsigned long) children);
502 pause ();
503 return 0;
504 }
505
506 pid = fork ();
507 if (pid == -1)
508 mu_diag_output (MU_DIAG_ERROR, "fork: %s", strerror (errno));
509 else if (pid == 0) /* Child. */
510 {
511 mu_tcp_server_shutdown (srv);
512 status = pconf->msrv->conn (fd, pconf->msrv->data,
513 pconf->timeout, pconf->transcript);
514 closelog ();
515 exit (status);
516 }
517 else
518 {
519 children++;
520 }
521 }
522 else
523 pconf->msrv->conn (fd, pconf->msrv->data,
524 pconf->timeout, pconf->transcript);
525
526 return 0;
527 }
528
529
530
531 unsigned short
532 get_port (mu_debug_t debug, char *p)
533 {
534 if (p)
535 {
536 char *q;
537 unsigned long n = strtoul (p, &q, 0);
538 if (*q == 0)
539 {
540 if (n > USHRT_MAX)
541 {
542 mu_debug_printf (debug, MU_DEBUG_ERROR,
543 _("invalid port number: %s\n"), p);
544 return 1;
545 }
546
547 return htons (n);
548 }
549 else
550 {
551 struct servent *sp = getservbyname (p, "tcp");
552 if (!sp)
553 return 0;
554 return sp->s_port;
555 }
556 }
557 return 0;
558 }
559
560 static int
561 get_family (char **pstr, sa_family_t *pfamily)
562 {
563 static struct family_tab
564 {
565 int len;
566 char *pfx;
567 int family;
568 } ftab[] = {
569 #define S(s,f) { sizeof (#s":") - 1, #s":", f }
570 S (file, AF_UNIX),
571 S (unix, AF_UNIX),
572 S (local, AF_UNIX),
573 S (socket, AF_UNIX),
574 S (inet, AF_INET),
575 S (tcp, AF_INET),
576 #undef S
577 { 0 }
578 };
579 struct family_tab *fp;
580
581 char *str = *pstr;
582 int len = strlen (str);
583 for (fp = ftab; fp->len; fp++)
584 {
585 if (len > fp->len && memcmp (str, fp->pfx, fp->len) == 0)
586 {
587 str += fp->len;
588 if (str[0] == '/' && str[1] == '/')
589 str += 2;
590 *pstr = str;
591 *pfamily = fp->family;
592 return 0;
593 }
594 }
595 return 1;
596 }
597
598 static int
599 is_ip_addr (const char *arg)
600 {
601 int dot_count;
602 int digit_count;
603
604 dot_count = 0;
605 digit_count = 0;
606 for (; *arg != 0 && *arg != ':'; arg++)
607 {
608 if (*arg == '.')
609 {
610 if (++dot_count > 3)
611 break;
612 digit_count = 0;
613 }
614 else if (!(isdigit (*arg) && ++digit_count <= 3))
615 return 0;
616 }
617 return dot_count == 3;
618 }
619
620 static int
621 server_block_begin (mu_debug_t debug, char *arg, mu_m_server_t msrv,
622 void **pdata)
623 {
624 char *p;
625 union
626 {
627 struct sockaddr s_sa;
628 struct sockaddr_in s_in;
629 struct sockaddr_un s_un;
630 }
631 s;
632 int salen = sizeof s.s_in;
633
634 s.s_sa.sa_family = AF_INET;
635
636 if (!arg)
637 {
638 s.s_in.sin_addr.s_addr = htonl (INADDR_ANY);
639 s.s_in.sin_port = htons (msrv->defport);
640 }
641 else
642 {
643 unsigned short n;
644 int len;
645
646 if (!is_ip_addr (arg) && get_family (&arg, &s.s_sa.sa_family))
647 {
648 mu_debug_printf (debug, MU_DEBUG_ERROR, _("invalid family\n"));
649 return 1;
650 }
651
652 switch (s.s_in.sin_family)
653 {
654 case AF_INET:
655 if ((n = get_port (debug, arg)))
656 {
657 s.s_in.sin_addr.s_addr = htonl (INADDR_ANY);
658 s.s_in.sin_port = htons (n);
659 }
660 else
661 {
662 p = strchr (arg, ':');
663 if (p)
664 *p++ = 0;
665 if (inet_aton (arg, &s.s_in.sin_addr) == 0)
666 {
667 struct hostent *hp = gethostbyname (arg);
668 if (hp)
669 s.s_in.sin_addr.s_addr = *(unsigned long *)hp->h_addr;
670 else
671 {
672 mu_debug_printf (debug, MU_DEBUG_ERROR,
673 _("invalid IP address: %s\n"), arg);
674 return 1;
675 }
676 }
677 if (p)
678 {
679 n = get_port (debug, p);
680 if (!n)
681 {
682 mu_debug_printf (debug, MU_DEBUG_ERROR,
683 _("invalid port number: %s\n"), p);
684 return 1;
685 }
686 s.s_in.sin_port = n;
687 }
688 else if (msrv->defport)
689 s.s_in.sin_port = htons (msrv->defport);
690 else
691 {
692 mu_debug_printf (debug, MU_DEBUG_ERROR,
693 _("missing port number\n"));
694 return 1;
695 }
696 }
697 break;
698
699 case AF_UNIX:
700 salen = sizeof s.s_un;
701 len = strlen (arg);
702 if (len > sizeof s.s_un.sun_path - 1)
703 {
704 mu_error (_("%s: file name too long"), arg);
705 return 1;
706 }
707 strcpy (s.s_un.sun_path, arg);
708 break;
709 }
710 }
711
712 *pdata = add_server (msrv, &s.s_sa, salen);
713 return 0;
714 }
715
716 static int
717 server_section_parser (enum mu_cfg_section_stage stage,
718 const mu_cfg_node_t *node,
719 const char *section_label, void **section_data,
720 void *call_data,
721 mu_cfg_tree_t *tree)
722 {
723 switch (stage)
724 {
725 case mu_cfg_section_start:
726 {
727 /* FIXME: should not modify 2nd arg, or it should not be const */
728 return server_block_begin (tree->debug, node->tag_label,
729 *section_data, section_data);
730 }
731 break;
732
733 case mu_cfg_section_end:
734 {
735 struct m_srv_config *pconf = *section_data;
736 if (pconf->acl)
737 mu_tcp_server_set_acl (pconf->tcpsrv, pconf->acl);
738 }
739 break;
740 }
741 return 0;
742 }
743
744 static int
745 _cb_daemon_mode (mu_debug_t debug, void *data, char *arg)
746 {
747 int *pmode = data;
748
749 if (strcmp (arg, "inetd") == 0
750 || strcmp (arg, "interactive") == 0)
751 *pmode = MODE_INTERACTIVE;
752 else if (strcmp (arg, "daemon") == 0)
753 *pmode = MODE_DAEMON;
754 else
755 {
756 mu_cfg_format_error (debug, MU_DEBUG_ERROR, _("unknown daemon mode"));
757 return 1;
758 }
759 return 0;
760 }
761
762 static struct mu_cfg_param dot_server_cfg_param[] = {
763 { "max-children", mu_cfg_size,
764 NULL, mu_offsetof (struct _mu_m_server,max_children), NULL,
765 N_("Maximum number of children processes to run simultaneously.") },
766 { "mode", mu_cfg_callback,
767 NULL, mu_offsetof (struct _mu_m_server,mode), _cb_daemon_mode,
768 N_("Set daemon mode (either inetd (or interactive) or daemon)."),
769 N_("mode") },
770 { "foreground", mu_cfg_bool,
771 NULL, mu_offsetof (struct _mu_m_server, foreground), NULL,
772 N_("Run in foreground.") },
773 { "pidfile", mu_cfg_string,
774 NULL, mu_offsetof (struct _mu_m_server,pidfile), NULL,
775 N_("Store PID of the master process in this file."),
776 N_("file") },
777 { "port", mu_cfg_ushort,
778 NULL, mu_offsetof (struct _mu_m_server,defport), NULL,
779 N_("Default port number.") },
780 { "timeout", mu_cfg_time,
781 NULL, mu_offsetof (struct _mu_m_server,timeout), NULL,
782 N_("Set idle timeout.") },
783 { "server", mu_cfg_section, NULL, 0, NULL,
784 N_("Server configuration.") },
785 { "acl", mu_cfg_section, NULL, mu_offsetof (struct _mu_m_server,acl), NULL,
786 N_("Per-server access control list") },
787 { NULL }
788 };
789
790 static struct mu_cfg_param server_cfg_param[] = {
791 { "single-process", mu_cfg_bool,
792 NULL, mu_offsetof (struct m_srv_config, single_process), NULL,
793 N_("Run this server in foreground.") },
794 { "transcript", mu_cfg_bool,
795 NULL, mu_offsetof (struct m_srv_config, transcript), NULL,
796 N_("Log the session transcript.") },
797 { "timeout", mu_cfg_time,
798 NULL, mu_offsetof (struct m_srv_config, timeout), NULL,
799 N_("Set idle timeout.") },
800 { "acl", mu_cfg_section,
801 NULL, mu_offsetof (struct m_srv_config, acl), NULL,
802 N_("Global access control list.") },
803 { NULL }
804 };
805
806 void
807 mu_m_server_cfg_init ()
808 {
809 struct mu_cfg_section *section;
810 if (mu_create_canned_section ("server", &section) == 0)
811 {
812 section->parser = server_section_parser;
813 section->label = N_("ipaddr[:port]");
814 mu_cfg_section_add_params (section, server_cfg_param);
815 }
816 if (mu_create_canned_section (".server", &section) == 0)
817 {
818 mu_cfg_section_add_params (section, dot_server_cfg_param);
819 }
820 }
821
822
823
1 /* GNU Mailutils -- a suite of utilities for electronic mail 1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2007 Free Software Foundation, Inc. 2 Copyright (C) 2007, 2008 Free Software Foundation, Inc.
3 3
4 This program is free software; you can redistribute it and/or modify it 4 This program is free software; you can redistribute it and/or modify it
5 under the terms of the GNU General Public License as published by the 5 under the terms of the GNU General Public License as published by the
...@@ -125,7 +125,11 @@ mu_diag_syslog_printer (void *data, mu_log_level_t level, const char *buf) ...@@ -125,7 +125,11 @@ mu_diag_syslog_printer (void *data, mu_log_level_t level, const char *buf)
125 { 125 {
126 int len = strlen (buf); 126 int len = strlen (buf);
127 if (len > 0 && buf[len-1] == '\n') 127 if (len > 0 && buf[len-1] == '\n')
128 {
129 len--;
130 if (len > 0 && buf[len-1] == '\r')
128 len--; 131 len--;
132 }
129 syslog (mu_diag_level_to_syslog (level), "%-.*s", len, buf); 133 syslog (mu_diag_level_to_syslog (level), "%-.*s", len, buf);
130 return 0; 134 return 0;
131 } 135 }
......
...@@ -21,7 +21,9 @@ ...@@ -21,7 +21,9 @@
21 #include <sys/time.h> 21 #include <sys/time.h>
22 #include <sys/types.h> 22 #include <sys/types.h>
23 #include <sys/socket.h> 23 #include <sys/socket.h>
24 #include <sys/stat.h>
24 #include <netinet/in.h> 25 #include <netinet/in.h>
26 #include <sys/un.h>
25 #include <arpa/inet.h> 27 #include <arpa/inet.h>
26 #include <unistd.h> 28 #include <unistd.h>
27 #include <stdlib.h> 29 #include <stdlib.h>
...@@ -31,12 +33,14 @@ ...@@ -31,12 +33,14 @@
31 #include <mailutils/debug.h> 33 #include <mailutils/debug.h>
32 #include <mailutils/diag.h> 34 #include <mailutils/diag.h>
33 #include <mailutils/errno.h> 35 #include <mailutils/errno.h>
36 #include <mailutils/nls.h>
34 37
35 38
36 struct _mu_tcp_server 39 struct _mu_tcp_server
37 { 40 {
38 char *ident; 41 char *ident;
39 struct sockaddr_in addr; 42 struct sockaddr *addr;
43 int addrlen;
40 int backlog; 44 int backlog;
41 int fd; 45 int fd;
42 mu_debug_t debug; 46 mu_debug_t debug;
...@@ -50,8 +54,8 @@ struct _mu_tcp_server ...@@ -50,8 +54,8 @@ struct _mu_tcp_server
50 #define IDENTSTR(s) ((s)->ident ? (s)->ident : "default") 54 #define IDENTSTR(s) ((s)->ident ? (s)->ident : "default")
51 55
52 int 56 int
53 mu_tcp_server_create (mu_tcp_server_t *psrv, 57 mu_tcp_server_create (mu_tcp_server_t *psrv, struct sockaddr *addr,
54 struct sockaddr_in *addr) 58 int addrlen)
55 { 59 {
56 struct _mu_tcp_server *srv; 60 struct _mu_tcp_server *srv;
57 mu_log_level_t level; 61 mu_log_level_t level;
...@@ -59,8 +63,15 @@ mu_tcp_server_create (mu_tcp_server_t *psrv, ...@@ -59,8 +63,15 @@ mu_tcp_server_create (mu_tcp_server_t *psrv,
59 srv = calloc (1, sizeof *srv); 63 srv = calloc (1, sizeof *srv);
60 if (!srv) 64 if (!srv)
61 return ENOMEM; 65 return ENOMEM;
62 srv->addr = *addr; 66 srv->addr = calloc (1, addrlen);
63 level = mu_global_debug_level ("mailbox"); 67 if (!srv->addr)
68 {
69 free (srv);
70 return ENOMEM;
71 }
72 memcpy (srv->addr, addr, addrlen);
73 srv->addrlen = addrlen;
74 level = mu_global_debug_level ("tcp_server");
64 if (level) 75 if (level)
65 { 76 {
66 mu_debug_create (&srv->debug, NULL); 77 mu_debug_create (&srv->debug, NULL);
...@@ -84,6 +95,7 @@ mu_tcp_server_destroy (mu_tcp_server_t *psrv) ...@@ -84,6 +95,7 @@ mu_tcp_server_destroy (mu_tcp_server_t *psrv)
84 if (srv->f_free) 95 if (srv->f_free)
85 srv->f_free (srv->data); 96 srv->f_free (srv->data);
86 close (srv->fd); 97 close (srv->fd);
98 free (srv->addr);
87 free (srv->ident); 99 free (srv->ident);
88 free (srv); 100 free (srv);
89 *psrv = NULL; 101 *psrv = NULL;
...@@ -169,20 +181,40 @@ mu_tcp_server_set_data (mu_tcp_server_t srv, ...@@ -169,20 +181,40 @@ mu_tcp_server_set_data (mu_tcp_server_t srv,
169 return 0; 181 return 0;
170 } 182 }
171 183
184 static int
185 family_to_proto (int family)
186 {
187 switch (family)
188 {
189 case AF_UNIX:
190 return PF_UNIX;
191
192 case AF_INET:
193 return PF_INET;
194
195 default:
196 abort ();
197 }
198 }
199
172 int 200 int
173 mu_tcp_server_open (mu_tcp_server_t srv) 201 mu_tcp_server_open (mu_tcp_server_t srv)
174 { 202 {
175 int fd; 203 int fd;
176 int t;
177 204
178 if (!srv || srv->fd != -1) 205 if (!srv || srv->fd != -1)
179 return EINVAL; 206 return EINVAL;
180 207
181 MU_DEBUG3 (srv->debug, MU_DEBUG_TRACE0, 208 if (mu_debug_check_level (srv->debug, MU_DEBUG_TRACE0))
182 "opening server \"%s\" %s:%d\n", IDENTSTR (srv), 209 {
183 inet_ntoa (srv->addr.sin_addr), ntohs (srv->addr.sin_port)); 210 char *p = mu_sockaddr_to_astr (srv->addr, srv->addrlen);
211 __MU_DEBUG2 (srv->debug, MU_DEBUG_TRACE0,
212 "opening server \"%s\" %s\n", IDENTSTR (srv),
213 p);
214 free (p);
215 }
184 216
185 fd = socket (PF_INET, SOCK_STREAM, 0); 217 fd = socket (family_to_proto (srv->addr->sa_family), SOCK_STREAM, 0);
186 if (fd == -1) 218 if (fd == -1)
187 { 219 {
188 MU_DEBUG2 (srv->debug, MU_DEBUG_ERROR, 220 MU_DEBUG2 (srv->debug, MU_DEBUG_ERROR,
...@@ -190,10 +222,52 @@ mu_tcp_server_open (mu_tcp_server_t srv) ...@@ -190,10 +222,52 @@ mu_tcp_server_open (mu_tcp_server_t srv)
190 return errno; 222 return errno;
191 } 223 }
192 224
225 switch (srv->addr->sa_family)
226 {
227 case AF_UNIX:
228 {
229 struct stat st;
230 struct sockaddr_un *s_un = (struct sockaddr_un *) srv->addr;
231
232 if (stat (s_un->sun_path, &st))
233 {
234 if (errno != ENOENT)
235 {
236 MU_DEBUG3 (srv->debug, MU_DEBUG_ERROR,
237 _("%s: file %s exists but cannot be stat'd: %s"),
238 IDENTSTR (srv),
239 s_un->sun_path,
240 mu_strerror (errno));
241 return EAGAIN;
242 }
243 }
244 else if (!S_ISSOCK (st.st_mode))
245 {
246 MU_DEBUG2 (srv->debug, MU_DEBUG_ERROR,
247 _("%s: file %s is not a socket"),
248 IDENTSTR (srv), s_un->sun_path);
249 return EAGAIN;
250 }
251 else if (unlink (s_un->sun_path))
252 {
253 MU_DEBUG3 (srv->debug, MU_DEBUG_ERROR,
254 _("%s: cannot unlink file %s: %s"),
255 IDENTSTR (srv), s_un->sun_path, mu_strerror (errno));
256 return EAGAIN;
257 }
258 }
259 break;
260
261 case AF_INET:
262 {
263 int t;
264
193 t = 1; 265 t = 1;
194 setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &t, sizeof (t)); 266 setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &t, sizeof (t));
267 }
268 }
195 269
196 if (bind (fd, (struct sockaddr *) &srv->addr, sizeof (srv->addr)) == -1) 270 if (bind (fd, srv->addr, srv->addrlen) == -1)
197 { 271 {
198 MU_DEBUG2 (srv->debug, MU_DEBUG_ERROR, 272 MU_DEBUG2 (srv->debug, MU_DEBUG_ERROR,
199 "%s: bind: %s\n", IDENTSTR (srv), mu_strerror (errno)); 273 "%s: bind: %s\n", IDENTSTR (srv), mu_strerror (errno));
...@@ -218,10 +292,14 @@ mu_tcp_server_shutdown (mu_tcp_server_t srv) ...@@ -218,10 +292,14 @@ mu_tcp_server_shutdown (mu_tcp_server_t srv)
218 { 292 {
219 if (!srv || srv->fd != -1) 293 if (!srv || srv->fd != -1)
220 return EINVAL; 294 return EINVAL;
221 MU_DEBUG4 (srv->debug, MU_DEBUG_TRACE0, 295 if (mu_debug_check_level (srv->debug, MU_DEBUG_TRACE0))
222 "closing server \"%s\" %s:%d, fd %d\n", IDENTSTR (srv), 296 {
223 inet_ntoa (srv->addr.sin_addr), ntohs (srv->addr.sin_port), 297 char *p = mu_sockaddr_to_astr (srv->addr, srv->addrlen);
224 srv->fd); 298 __MU_DEBUG2 (srv->debug, MU_DEBUG_TRACE0,
299 "closing server \"%s\" %s\n", IDENTSTR (srv),
300 p);
301 free (p);
302 }
225 close (srv->fd); 303 close (srv->fd);
226 return 0; 304 return 0;
227 } 305 }
...@@ -231,13 +309,18 @@ mu_tcp_server_accept (mu_tcp_server_t srv, void *call_data) ...@@ -231,13 +309,18 @@ mu_tcp_server_accept (mu_tcp_server_t srv, void *call_data)
231 { 309 {
232 int rc; 310 int rc;
233 int connfd; 311 int connfd;
234 struct sockaddr_in client; 312 union
313 {
314 struct sockaddr sa;
315 char buffer[512];
316 } client;
317
235 socklen_t size = sizeof (client); 318 socklen_t size = sizeof (client);
236 319
237 if (!srv || srv->fd == -1) 320 if (!srv || srv->fd == -1)
238 return EINVAL; 321 return EINVAL;
239 322
240 connfd = accept (srv->fd, (struct sockaddr *) &client, &size); 323 connfd = accept (srv->fd, &client.sa, &size);
241 if (connfd == -1) 324 if (connfd == -1)
242 { 325 {
243 int ec = errno; 326 int ec = errno;
...@@ -252,26 +335,26 @@ mu_tcp_server_accept (mu_tcp_server_t srv, void *call_data) ...@@ -252,26 +335,26 @@ mu_tcp_server_accept (mu_tcp_server_t srv, void *call_data)
252 if (srv->acl) 335 if (srv->acl)
253 { 336 {
254 mu_acl_result_t res; 337 mu_acl_result_t res;
255 int rc = mu_acl_check_sockaddr (srv->acl, (struct sockaddr *) &client, 338 int rc = mu_acl_check_sockaddr (srv->acl, &client.sa, size, &res);
256 size, &res);
257 if (rc) 339 if (rc)
258 MU_DEBUG2 (srv->debug, MU_DEBUG_ERROR, 340 MU_DEBUG2 (srv->debug, MU_DEBUG_ERROR,
259 "%s: mu_acl_check_sockaddr: %s\n", 341 "%s: mu_acl_check_sockaddr: %s\n",
260 IDENTSTR (srv), strerror (rc)); 342 IDENTSTR (srv), strerror (rc));
261 if (res == mu_acl_result_deny) 343 if (res == mu_acl_result_deny)
262 { 344 {
263 mu_diag_output (MU_DIAG_INFO, "Denying connection from %s:%d", 345 char *p = mu_sockaddr_to_astr (srv->addr, srv->addrlen);
264 inet_ntoa (client.sin_addr), 346 mu_diag_output (MU_DIAG_INFO, "Denying connection from %s", p);
265 ntohs (client.sin_port)); 347 free (p);
348
266 close (connfd); 349 close (connfd);
267 return 0; 350 return 0;
268 } 351 }
269 } 352 }
270 rc = srv->f_conn (connfd, &client, srv->data, call_data, srv); 353 rc = srv->f_conn (connfd, &client.sa, size, srv->data, call_data, srv);
271 if (rc) 354 if (rc)
272 mu_tcp_server_shutdown (srv); 355 mu_tcp_server_shutdown (srv);
273 close (connfd); 356 close (connfd);
274 return 0; 357 return rc;
275 } 358 }
276 359
277 int 360 int
...@@ -298,11 +381,22 @@ mu_tcp_server_get_fd (mu_tcp_server_t srv) ...@@ -298,11 +381,22 @@ mu_tcp_server_get_fd (mu_tcp_server_t srv)
298 } 381 }
299 382
300 int 383 int
301 mu_tcp_server_get_sockaddr (mu_tcp_server_t srv, struct sockaddr_in *s) 384 mu_tcp_server_get_sockaddr (mu_tcp_server_t srv, struct sockaddr *s, int *size)
302 { 385 {
386 int len;
387
303 if (!srv || !s) 388 if (!srv || !s)
304 return EINVAL; 389 return EINVAL;
305 memcpy (s, &srv->addr, sizeof (*s)); 390 if (s == 0)
391 len = srv->addrlen;
392 else
393 {
394 len = *size;
395 if (len < srv->addrlen)
396 len = srv->addrlen;
397 memcpy (s, srv->addr, len);
398 }
399 *size = len;
306 return 0; 400 return 0;
307 } 401 }
308 402
......
...@@ -383,7 +383,7 @@ main (int argc, char *argv[]) ...@@ -383,7 +383,7 @@ main (int argc, char *argv[])
383 383
384 tickets = mu_tilde_expansion ("~/.tickets", "/", NULL); 384 tickets = mu_tilde_expansion ("~/.tickets", "/", NULL);
385 tickets_default = 1; 385 tickets_default = 1;
386 debug_level = MU_DEBUG_ERROR; 386 debug_level = MU_DEBUG_LEVEL_MASK (MU_DEBUG_ERROR);
387 log_facility = 0; 387 log_facility = 0;
388 388
389 if (mu_app_init (&argp, sieve_argp_capa, sieve_cfg_param, 389 if (mu_app_init (&argp, sieve_argp_capa, sieve_cfg_param,
......