* 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.
Showing
30 changed files
with
1500 additions
and
776 deletions
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 | } | ... | ... |
mailbox/msrv.c
0 → 100644
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", §ion) == 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", §ion) == 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, | ... | ... |
-
Please register or sign in to post a comment