Commit 77d0b9df 77d0b9dffcee9761077828fb1725314590bff3e7 by Sergey Poznyakoff

* TODO, NEWS: Update.

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

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

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

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

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

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

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

* po/POTFILES.in: Update.
1 parent c060b5fd
2008-01-04 Sergey Poznyakoff <gray@gnu.org.ua>
* 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.
2008-01-02 Sergey Poznyakoff <gray@gnu.org.ua>
* include/mailutils/property.h: Update
......
GNU mailutils NEWS -- history of user-visible changes. 2007-12-30
GNU mailutils NEWS -- history of user-visible changes. 2008-01-04
Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
See the end of file for copying conditions.
......@@ -72,6 +72,11 @@ pop3d, maidag). The support is controlled at compile time by the
is enabled if libwrap presence is detected. A set of configuration
file statements are provided for fine tuning TCP wrappers at run-time.
** pop3d and imap4d ports.
Pop3d and imap4d can be configured to listen on several different
IP addresses/ports (or even local sockets) simultaneously.
** pop3d: Fixed APOP handling.
** imap4d supports PREAUTH mode.
......
GNU mailutils TODO list. 2007-12-28
GNU mailutils TODO list. 2008-01-03
Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006,
2007 Free Software Foundation, Inc.
2007, 2008 Free Software Foundation, Inc.
* Configuration callback functions should not modify node->tag and node->label.
* Debug handling in cfg vs. argp
* Fix folder_imap_list in libproto/imap/folder.c
......
......@@ -18,10 +18,8 @@
## 02110-1301 USA
EXTRA_DIST = \
comsat.conf\
dot.biffrc\
gnu-imap4d.pam\
gnu-pop3d.pam\
mailutils.dict\
mailutils.rc
mailutils.dict
......
......@@ -35,15 +35,17 @@
mu_server_t server;
int
echo_conn (int fd, struct sockaddr_in *s, void *server_data, void *call_data,
echo_conn (int fd, struct sockaddr *s, int len,
void *server_data, void *call_data,
mu_tcp_server_t srv)
{
struct sockaddr_in srv_addr;
struct sockaddr_in srv_addr, *s_in = (struct sockaddr_in *)s;
int addrlen = sizeof srv_addr;
pid_t pid;
char buf[512];
FILE *in, *out;
mu_tcp_server_get_sockaddr (srv, &srv_addr);
mu_tcp_server_get_sockaddr (srv, (struct sockaddr *)&srv_addr, &addrlen);
pid = fork ();
if (pid == -1)
......@@ -57,7 +59,7 @@ echo_conn (int fd, struct sockaddr_in *s, void *server_data, void *call_data,
mu_diag_output (MU_DIAG_INFO, "%lu: opened connection %s:%d => %s:%d",
(unsigned long) pid,
inet_ntoa (srv_addr.sin_addr), ntohs (srv_addr.sin_port),
inet_ntoa (s->sin_addr), ntohs (s->sin_port));
inet_ntoa (s_in->sin_addr), ntohs (s_in->sin_port));
return 0;
}
......@@ -132,7 +134,7 @@ create_server (char *arg)
}
s.sin_port = htons (n);
MU_ASSERT (mu_tcp_server_create (&tcpsrv, &s));
MU_ASSERT (mu_tcp_server_create (&tcpsrv, (struct sockaddr*) &s, sizeof s));
MU_ASSERT (mu_tcp_server_open (tcpsrv));
MU_ASSERT (mu_tcp_server_set_conn (tcpsrv, echo_conn));
MU_ASSERT (mu_server_add_connection (server,
......
......@@ -377,7 +377,7 @@ com_verbose (char *arg)
{
mu_debug_t debug;
mu_debug_create (&debug, NULL);
mu_debug_set_level (debug, MU_DEBUG_PROT);
mu_debug_set_level (debug, MU_DEBUG_LEVEL_UPTO (MU_DEBUG_PROT));
status = mu_nntp_set_debug (nntp, debug);
}
else
......
......@@ -364,7 +364,7 @@ com_verbose (char *arg)
{
mu_debug_t debug;
mu_debug_create (&debug, NULL);
mu_debug_set_level (debug, MU_DEBUG_PROT);
mu_debug_set_level (debug, MU_DEBUG_LEVEL_UPTO (MU_DEBUG_PROT));
status = mu_pop3_set_debug (pop3, debug);
}
else
......
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 1999, 2001, 2002, 2003, 2004,
2005, 2006, 2007 Free Software Foundation, Inc.
2005, 2006, 2007, 2008 Free Software Foundation, Inc.
GNU Mailutils is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -24,20 +24,15 @@
#include "mailutils/libargp.h"
#include "tcpwrap.h"
mu_m_server_t server;
unsigned int idle_timeout;
int imap4d_transcript;
mu_mailbox_t mbox;
char *homedir;
int state = STATE_NONAUTH;
struct mu_auth_data *auth_data;
struct mu_gocs_daemon default_gocs_daemon = {
MODE_INTERACTIVE, /* Start in interactive (inetd) mode */
20, /* Default maximum number of children */
143, /* Standard IMAP4 port */
1800, /* RFC2060: 30 minutes. */
0, /* No transcript by default */
NULL /* No PID file by default */
};
int login_disabled; /* Disable LOGIN command */
int tls_required; /* Require STARTTLS */
int create_home_dir; /* Create home directory if it does not
......@@ -51,33 +46,34 @@ int ident_port;
char *ident_keyfile;
int ident_encrypt_only;
mu_acl_t imap4d_acl;
/* Number of child processes. */
size_t children;
const char *program_version = "imap4d (" PACKAGE_STRING ")";
static char doc[] = N_("GNU imap4d -- the IMAP4D daemon");
#define ARG_LOGIN_DISABLED 256
#define ARG_TLS_REQUIRED 257
#define ARG_CREATE_HOME_DIR 258
#define ARG_OPTION_PREAUTH 259
#define OPT_LOGIN_DISABLED 256
#define OPT_TLS_REQUIRED 257
#define OPT_CREATE_HOME_DIR 258
#define OPT_PREAUTH 259
#define OPT_FOREGROUND 260
static struct argp_option options[] = {
{ "foreground", OPT_FOREGROUND, 0, 0, N_("Remain in foreground."), 0},
{ "inetd", 'i', 0, 0, N_("Run in inetd mode"), 0},
{ "daemon", 'd', N_("NUMBER"), OPTION_ARG_OPTIONAL,
N_("Runs in daemon mode with a maximum of NUMBER children"), 0 },
{"other-namespace", 'O', N_("PATHLIST"), OPTION_HIDDEN,
N_("Set the `other' namespace"), 0},
{"shared-namespace", 'S', N_("PATHLIST"), OPTION_HIDDEN,
N_("Set the `shared' namespace"), 0},
{"login-disabled", ARG_LOGIN_DISABLED, NULL, OPTION_HIDDEN,
{"login-disabled", OPT_LOGIN_DISABLED, NULL, OPTION_HIDDEN,
N_("Disable LOGIN command")},
{"create-home-dir", ARG_CREATE_HOME_DIR, N_("MODE"),
{"create-home-dir", OPT_CREATE_HOME_DIR, N_("MODE"),
OPTION_ARG_OPTIONAL|OPTION_HIDDEN,
N_("Create home directory, if it does not exist")},
{"preauth", ARG_OPTION_PREAUTH, NULL, 0,
{"preauth", OPT_PREAUTH, NULL, 0,
N_("Start in preauth mode") },
#ifdef WITH_TLS
{"tls-required", ARG_TLS_REQUIRED, NULL, OPTION_HIDDEN,
{"tls-required", OPT_TLS_REQUIRED, NULL, OPTION_HIDDEN,
N_("Always require STARTTLS before entering authentication phase")},
#endif
{NULL, 0, NULL, 0, NULL, 0}
......@@ -97,7 +93,6 @@ static struct argp argp = {
};
static const char *imap4d_capa[] = {
"daemon",
"auth",
"common",
"debug",
......@@ -108,8 +103,6 @@ static const char *imap4d_capa[] = {
NULL
};
static void imap4d_daemon_init (void);
static void imap4d_daemon (unsigned int, unsigned int);
static int imap4d_mainloop (int, FILE *, FILE *);
static error_t
......@@ -119,6 +112,20 @@ imap4d_parse_opt (int key, char *arg, struct argp_state *state)
switch (key)
{
case 'd':
mu_argp_node_list_new (&lst, "mode", "daemon");
if (arg)
mu_argp_node_list_new (&lst, "max-children", arg);
break;
case 'i':
mu_argp_node_list_new (&lst, "mode", "inetd");
break;
case OPT_FOREGROUND:
mu_argp_node_list_new (&lst, "foreground", "yes");
break;
case 'O':
mu_argp_node_list_new (&lst, "other-namespace", arg);
break;
......@@ -127,23 +134,23 @@ imap4d_parse_opt (int key, char *arg, struct argp_state *state)
mu_argp_node_list_new (&lst, "shared-namespace", arg);
break;
case ARG_LOGIN_DISABLED:
case OPT_LOGIN_DISABLED:
mu_argp_node_list_new (&lst, "login-disabled", "yes");
break;
case ARG_CREATE_HOME_DIR:
case OPT_CREATE_HOME_DIR:
mu_argp_node_list_new (&lst, "create-home-dir", "yes");
if (arg)
mu_argp_node_list_new (&lst, "home-dir-mode", arg);
break;
#ifdef WITH_TLS
case ARG_TLS_REQUIRED:
case OPT_TLS_REQUIRED:
mu_argp_node_list_new (&lst, "tls-required", "yes");
break;
#endif
case ARG_OPTION_PREAUTH:
case OPT_PREAUTH:
preauth_mode = preauth_stdio;
break;
......@@ -309,140 +316,13 @@ static struct mu_cfg_param imap4d_cfg_param[] = {
N_("Name of DES keyfile for decoding ecrypted ident responses.") },
{ "ident-entrypt-only", mu_cfg_bool, &ident_encrypt_only, 0, NULL,
N_("Use only encrypted ident responses.") },
{ "acl", mu_cfg_section, },
{ ".server", mu_cfg_section, NULL, 0, NULL,
N_("Server configuration.") },
TCP_WRAPPERS_CONFIG
{ NULL }
};
int
main (int argc, char **argv)
{
struct group *gr;
int status = EXIT_SUCCESS;
/* Native Language Support */
mu_init_nls ();
state = STATE_NONAUTH; /* Starting state in non-auth. */
MU_AUTH_REGISTER_ALL_MODULES ();
/* Register the desired formats. */
mu_register_local_mbox_formats ();
imap4d_capability_init ();
mu_gocs_daemon = default_gocs_daemon;
#ifdef WITH_TLS
mu_gocs_register ("tls", mu_tls_module_init);
#endif /* WITH_TLS */
#ifdef WITH_GSASL
mu_gocs_register ("gsasl", mu_gsasl_module_init);
#endif
mu_tcpwrapper_cfg_init ();
mu_acl_cfg_init ();
mu_argp_init (program_version, NULL);
if (mu_app_init (&argp, imap4d_capa, imap4d_cfg_param,
argc, argv, 0, NULL, &imap4d_acl))
exit (1);
if (login_disabled)
imap4d_capability_add (IMAP_CAPA_LOGINDISABLED);
#ifdef WITH_TLS
if (tls_required)
imap4d_capability_add (IMAP_CAPA_XTLSREQUIRED);
#endif
auth_gssapi_init ();
auth_gsasl_init ();
#ifdef USE_LIBPAM
if (!mu_pam_service)
mu_pam_service = "gnu-imap4d";
#endif
if (mu_gocs_daemon.mode == MODE_DAEMON)
{
/* Normal operation: */
/* First we want our group to be mail so we can access the spool. */
gr = getgrnam ("mail");
if (gr == NULL)
{
perror (_("Error getting mail group"));
exit (1);
}
if (setgid (gr->gr_gid) == -1)
{
perror (_("Error setting mail group"));
exit (1);
}
}
/* Set the signal handlers. */
signal (SIGINT, imap4d_signal);
signal (SIGQUIT, imap4d_signal);
signal (SIGILL, imap4d_signal);
signal (SIGBUS, imap4d_signal);
signal (SIGFPE, imap4d_signal);
signal (SIGSEGV, imap4d_signal);
signal (SIGTERM, imap4d_signal);
signal (SIGSTOP, imap4d_signal);
signal (SIGPIPE, imap4d_signal);
/*signal (SIGPIPE, SIG_IGN); */
signal (SIGABRT, imap4d_signal);
if (mu_gocs_daemon.mode == MODE_DAEMON)
imap4d_daemon_init ();
else
{
/* Make sure we are in the root. */
chdir ("/");
}
/* Set up for syslog. */
openlog ("gnu-imap4d", LOG_PID, log_facility);
/* Redirect any stdout error from the library to syslog, they
should not go to the client. */
{
mu_debug_t debug;
mu_diag_get_debug (&debug);
mu_debug_set_print (debug, mu_diag_syslog_printer, NULL);
/* FIXME: this should be done automatically by cfg */
if (imap4d_acl)
{
mu_acl_get_debug (imap4d_acl, &debug);
mu_debug_set_print (debug, mu_debug_syslog_printer, NULL);
}
}
umask (S_IROTH | S_IWOTH | S_IXOTH); /* 007 */
if (mu_gocs_daemon.pidfile)
{
mu_daemon_create_pidfile (mu_gocs_daemon.pidfile);
}
/* Check TLS environment, i.e. cert and key files */
#ifdef WITH_TLS
starttls_init ();
#endif /* WITH_TLS */
/* Actually run the daemon. */
if (mu_gocs_daemon.mode == MODE_DAEMON)
imap4d_daemon (mu_gocs_daemon.maxchildren, mu_gocs_daemon.port);
/* exit (0) -- no way out of daemon except a signal. */
else
status = imap4d_mainloop (fileno (stdin), stdin, stdout);
/* Close the syslog connection and exit. */
closelog ();
return status;
}
int
imap4d_session_setup0 ()
{
homedir = mu_normalize_path (strdup (auth_data->dir), "/");
......@@ -499,44 +379,13 @@ imap4d_mainloop (int fd, FILE *infile, FILE *outfile)
{
if (get_client_address (fd, &cs) == 0)
{
if (imap4d_acl)
{
mu_acl_result_t res;
int rc = mu_acl_check_sockaddr (imap4d_acl,
(struct sockaddr*) &cs,
sizeof (cs),
&res);
if (rc)
{
mu_error (_("Access from %s blocked: cannot check ACLs: %s"),
inet_ntoa (cs.sin_addr), mu_strerror (rc));
return 1;
}
switch (res)
{
case mu_acl_result_undefined:
mu_diag_output (MU_DIAG_INFO,
_("%s: undefined ACL result; access allowed"),
inet_ntoa (cs.sin_addr));
break;
case mu_acl_result_accept:
break;
case mu_acl_result_deny:
mu_error (_("Access from %s blocked."),
inet_ntoa (cs.sin_addr));
return 1;
}
}
if (!mu_tcpwrapper_access (fd))
{
mu_error (_("Access from %s blocked."), inet_ntoa (cs.sin_addr));
return 1;
}
}
else if (mu_tcp_wrapper_enable || imap4d_acl)
else if (mu_tcp_wrapper_enable)
{
mu_error (_("Rejecting connection from unknown address"));
return 1;
......@@ -584,145 +433,172 @@ imap4d_mainloop (int fd, FILE *infile, FILE *outfile)
return EXIT_SUCCESS;
}
/* Sets things up for daemon mode. */
static void
imap4d_daemon_init (void)
int
imap4d_connection (int fd, void *data, time_t timeout, int transcript)
{
extern int daemon (int, int);
idle_timeout = timeout;
imap4d_transcript = transcript;
imap4d_mainloop (fd, fdopen (fd, "r"), fdopen (fd, "w"));
return 0;
}
/* Become a daemon. Take care to close inherited fds and to hold
first three one, in, out, err */
if (daemon (0, 0) < 0)
int
imap4d_check_home_dir (const char *dir, uid_t uid, gid_t gid)
{
struct stat st;
if (stat (homedir, &st))
{
perror (_("could not become daemon"));
exit (1);
if (errno == ENOENT && create_home_dir)
{
mode_t mode = umask (0);
int rc = mkdir (homedir, home_dir_mode);
umask (mode);
if (rc)
{
mu_error ("Cannot create home directory `%s': %s",
homedir, mu_strerror (errno));
return 1;
}
/* SIGCHLD is not ignore but rather use to do some simple load balancing. */
#ifdef HAVE_SIGACTION
if (chown (homedir, uid, gid))
{
struct sigaction act;
act.sa_handler = imap4d_sigchld;
sigemptyset (&act.sa_mask);
act.sa_flags = 0;
sigaction (SIGCHLD, &act, NULL);
mu_error ("Cannot set owner for home directory `%s': %s",
homedir, mu_strerror (errno));
return 1;
}
#else
signal (SIGCHLD, imap4d_sigchld);
#endif
}
}
return 0;
}
/* Runs GNU imap4d in standalone daemon mode. This opens and binds to a port
(default 143) then executes a imap4d_mainloop() upon accepting a connection.
It starts maxchildren child processes to listen to and accept socket
connections. */
static void
imap4d_daemon (unsigned int maxchildren, unsigned int port)
int
main (int argc, char **argv)
{
struct sockaddr_in server, client;
pid_t pid;
int listenfd, connfd;
size_t size;
struct group *gr;
int status = EXIT_SUCCESS;
listenfd = socket (PF_INET, SOCK_STREAM, 0);
if (listenfd == -1)
{
mu_diag_output (MU_DIAG_ERROR, "socket: %s", strerror (errno));
exit (1);
}
size = 1; /* Use size here to avoid making a new variable. */
setsockopt (listenfd, SOL_SOCKET, SO_REUSEADDR, &size, sizeof (size));
size = sizeof (server);
memset (&server, 0, size);
server.sin_family = AF_INET;
server.sin_addr.s_addr = htonl (INADDR_ANY);
server.sin_port = htons (port);
if (bind (listenfd, (struct sockaddr *) &server, size) == -1)
{
mu_diag_output (MU_DIAG_ERROR, "bind: %s", strerror (errno));
exit (1);
}
/* Native Language Support */
mu_init_nls ();
if (listen (listenfd, 128) == -1)
{
mu_diag_output (MU_DIAG_ERROR, "listen: %s", strerror (errno));
state = STATE_NONAUTH; /* Starting state in non-auth. */
MU_AUTH_REGISTER_ALL_MODULES ();
/* Register the desired formats. */
mu_register_local_mbox_formats ();
imap4d_capability_init ();
#ifdef WITH_TLS
mu_gocs_register ("tls", mu_tls_module_init);
#endif /* WITH_TLS */
#ifdef WITH_GSASL
mu_gocs_register ("gsasl", mu_gsasl_module_init);
#endif
mu_tcpwrapper_cfg_init ();
mu_acl_cfg_init ();
mu_m_server_cfg_init ();
mu_argp_init (program_version, NULL);
mu_m_server_create (&server, "GNU imap4d");
mu_m_server_set_conn (server, imap4d_connection);
mu_m_server_set_mode (server, MODE_INTERACTIVE);
mu_m_server_set_max_children (server, 20);
/* FIXME mu_m_server_set_pidfile (); */
mu_m_server_set_default_port (server, 143);
mu_m_server_set_timeout (server, 1800); /* RFC2060: 30 minutes. */
if (mu_app_init (&argp, imap4d_capa, imap4d_cfg_param,
argc, argv, 0, NULL, server))
exit (1);
}
mu_diag_output (MU_DIAG_INFO, _("GNU imap4d started"));
if (login_disabled)
imap4d_capability_add (IMAP_CAPA_LOGINDISABLED);
#ifdef WITH_TLS
if (tls_required)
imap4d_capability_add (IMAP_CAPA_XTLSREQUIRED);
#endif
auth_gssapi_init ();
auth_gsasl_init ();
for (;;)
{
if (children > maxchildren)
#ifdef USE_LIBPAM
if (!mu_pam_service)
mu_pam_service = "gnu-imap4d";
#endif
if (mu_m_server_mode (server) == MODE_DAEMON)
{
mu_diag_output (MU_DIAG_ERROR, _("Too many children (%s)"),
mu_umaxtostr (0, children));
pause ();
continue;
}
connfd = accept (listenfd, (struct sockaddr *) &client,
(socklen_t *) & size);
if (connfd == -1)
/* Normal operation: */
/* First we want our group to be mail so we can access the spool. */
gr = getgrnam ("mail");
if (gr == NULL)
{
if (errno == EINTR)
continue;
mu_diag_output (MU_DIAG_ERROR, "accept: %s", strerror (errno));
perror (_("Error getting mail group"));
exit (1);
}
pid = fork ();
if (pid == -1)
mu_diag_output (MU_DIAG_ERROR, "fork: %s", strerror (errno));
else if (pid == 0) /* Child. */
if (setgid (gr->gr_gid) == -1)
{
int status;
perror (_("Error setting mail group"));
exit (1);
}
}
close (listenfd);
/* Set the signal handlers. */
signal (SIGINT, imap4d_signal);
signal (SIGQUIT, imap4d_signal);
signal (SIGILL, imap4d_signal);
signal (SIGBUS, imap4d_signal);
signal (SIGFPE, imap4d_signal);
signal (SIGSEGV, imap4d_signal);
signal (SIGTERM, imap4d_signal);
signal (SIGSTOP, imap4d_signal);
signal (SIGPIPE, imap4d_signal);
/*signal (SIGPIPE, SIG_IGN); */
signal (SIGABRT, imap4d_signal);
status = imap4d_mainloop (connfd,
fdopen (connfd, "r"),
fdopen (connfd, "w"));
/* Set up for syslog. */
openlog ("gnu-imap4d", LOG_PID, log_facility);
close (connfd);
closelog ();
exit (status);
}
else
/* Redirect any stdout error from the library to syslog, they
should not go to the client. */
{
++children;
}
close (connfd);
mu_debug_t debug;
mu_diag_get_debug (&debug);
mu_debug_set_print (debug, mu_diag_syslog_printer, NULL);
mu_debug_default_printer = mu_debug_syslog_printer;
}
}
int
imap4d_check_home_dir (const char *dir, uid_t uid, gid_t gid)
{
struct stat st;
umask (S_IROTH | S_IWOTH | S_IXOTH); /* 007 */
if (stat (homedir, &st))
{
if (errno == ENOENT && create_home_dir)
{
mode_t mode = umask (0);
int rc = mkdir (homedir, home_dir_mode);
umask (mode);
if (rc)
/* Check TLS environment, i.e. cert and key files */
#ifdef WITH_TLS
starttls_init ();
#endif /* WITH_TLS */
/* Actually run the daemon. */
if (mu_m_server_mode (server) == MODE_DAEMON)
{
mu_error ("Cannot create home directory `%s': %s",
homedir, mu_strerror (errno));
return 1;
mu_m_server_begin (server);
status = mu_m_server_run (server);
mu_m_server_end (server);
mu_m_server_destroy (&server);
}
if (chown (homedir, uid, gid))
else
{
mu_error ("Cannot set owner for home directory `%s': %s",
homedir, mu_strerror (errno));
return 1;
}
}
/* Make sure we are in the root directory. */
chdir ("/");
status = imap4d_mainloop (fileno (stdin), stdin, stdout);
}
return 0;
if (status)
mu_error (_("Main loop status: %s"), mu_strerror (status));
/* Close the syslog connection and exit. */
closelog ();
return status != 0;
}
......
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 1999, 2001, 2002, 2003, 2004,
2005, 2006, 2007 Free Software Foundation, Inc.
2005, 2006, 2007, 2008 Free Software Foundation, Inc.
GNU Mailutils is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -97,6 +97,7 @@
#include <mailutils/daemon.h>
#include <mailutils/pam.h>
#include <mailutils/acl.h>
#include <mailutils/server.h>
#include <mu_asprintf.h>
#include <mu_umaxtostr.h>
......
......@@ -19,21 +19,6 @@
#define __USE_MISC
#include "imap4d.h"
RETSIGTYPE
imap4d_sigchld (int signo)
{
pid_t pid;
int status;
while ((pid = waitpid (-1, &status, WNOHANG)) > 0)
--children;
#ifndef HAVE_SIGACTION
/* On some system, signal implements the unreliable semantic and
has to be rearm. */
signal (signo, imap4d_sigchld);
#endif
}
/* Default signal handler to call the imap4d_bye() function */
RETSIGTYPE
......
/* cfg.h -- general-purpose configuration file parser
Copyright (C) 2007 Free Software Foundation, Inc.
Copyright (C) 2007, 2008 Free Software Foundation, Inc.
GNU Mailutils is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
......@@ -135,7 +135,7 @@ struct mu_cfg_param
const char *argname;
};
#define mu_offsetof(s,f) ((size_t)&((s*)0).f)
#define mu_offsetof(s,f) ((size_t)&((s*)0)->f)
#define MU_TARGET_REF(f) &f, 0
#define MU_TARGET_OFF(s,f) NULL, mu_offsetof(s,f)
......
/* GNU Mailutils -- a suite of utilities for electronic mail -*- c -*-
Copyright (C) 1999, 2000, 2005, 2007 Free Software Foundation, Inc.
Copyright (C) 1999, 2000, 2005, 2007, 2008 Free Software Foundation, Inc.
This library is free software; you can redistribute it and/or
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 *);
int mu_debug_level_from_string (const char *string, mu_log_level_t *plev,
mu_debug_t debug);
struct sockaddr;
void mu_sockaddr_to_str (struct sockaddr *sa, int salen,
char *bufptr, size_t buflen,
size_t *plen);
char *mu_sockaddr_to_astr (struct sockaddr *sa, int salen);
#define MU_ASSERT(expr) \
do \
......
......@@ -19,6 +19,7 @@
#define _MAILUTILS_SERVER_H
#include <mailutils/types.h>
#include <signal.h>
typedef int (*mu_conn_loop_fp) (int fd, void *conn_data, void *server_data);
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);
/* TCP server */
struct sockaddr_in;
typedef int (*mu_tcp_server_conn_fp) (int fd, struct sockaddr_in *s,
struct sockaddr;
typedef int (*mu_tcp_server_conn_fp) (int fd, struct sockaddr *s, int len,
void *server_data, void *call_data,
mu_tcp_server_t srv);
typedef int (*mu_tcp_server_intr_fp) (void *data, void *call_data);
typedef void (*mu_tcp_server_free_fp) (void *data);
int mu_tcp_server_create (mu_tcp_server_t *psrv, struct sockaddr_in *addr);
int mu_tcp_server_create (mu_tcp_server_t *psrv, struct sockaddr *addr,
int len);
int mu_tcp_server_destroy (mu_tcp_server_t *psrv);
int mu_tcp_server_set_debug (mu_tcp_server_t srv, mu_debug_t debug);
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);
int mu_tcp_server_accept (mu_tcp_server_t srv, void *call_data);
int mu_tcp_server_loop (mu_tcp_server_t srv, void *call_data);
int mu_tcp_server_get_fd (mu_tcp_server_t srv);
int mu_tcp_server_get_sockaddr (mu_tcp_server_t srv, struct sockaddr_in *s);
int mu_tcp_server_get_sockaddr (mu_tcp_server_t srv, struct sockaddr *s,
int *size);
/* m-server */
typedef int (*mu_m_server_conn_fp) (int, void *, time_t, int);
void mu_m_server_create (mu_m_server_t *psrv, const char *ident);
void mu_m_server_set_mode (mu_m_server_t srv, int mode);
void mu_m_server_set_conn (mu_m_server_t srv, mu_m_server_conn_fp f);
void mu_m_server_set_data (mu_m_server_t srv, void *data);
void mu_m_server_set_max_children (mu_m_server_t srv, size_t num);
int mu_m_server_set_pidfile (mu_m_server_t srv, const char *pidfile);
void mu_m_server_set_default_port (mu_m_server_t srv, int port);
void mu_m_server_set_timeout (mu_m_server_t srv, time_t t);
void mu_m_server_set_mode (mu_m_server_t srv, int mode);
void mu_m_server_set_sigset (mu_m_server_t srv, sigset_t *sigset);
int mu_m_server_mode (mu_m_server_t srv);
time_t mu_m_server_timeout (mu_m_server_t srv);
void mu_m_server_get_sigset (mu_m_server_t srv, sigset_t *sigset);
void mu_m_server_begin (mu_m_server_t msrv);
int mu_m_server_run (mu_m_server_t msrv);
void mu_m_server_cfg_init (void);
#endif
......
......@@ -108,6 +108,7 @@ typedef int mu_log_level_t;
typedef struct _mu_acl *mu_acl_t;
typedef struct _mu_server *mu_server_t;
typedef struct _mu_tcp_server *mu_tcp_server_t;
typedef struct _mu_m_server *mu_m_server_t;
#define MU_FOLDER_ATTRIBUTE_DIRECTORY 0x001
#define MU_FOLDER_ATTRIBUTE_FILE 0x002
......
......@@ -25,222 +25,7 @@
#include <signal.h>
#include <mu_umaxtostr.h>
typedef union
{
struct sockaddr sa;
struct sockaddr_in s_in;
struct sockaddr_un s_un;
} all_addr_t;
static int
lmtp_open_internal (int *pfd, mu_url_t url, const char *urlstr)
{
int fd;
int rc;
int t = 1;
char buffer[64];
all_addr_t addr;
int addrsize;
mode_t saved_umask;
rc = mu_url_get_scheme (url, buffer, sizeof buffer, NULL);
if (rc)
{
mu_error (_("%s: cannot get scheme from URL: %s"),
urlstr, mu_strerror(rc));
return EX_CONFIG;
}
memset (&addr, 0, sizeof addr);
if (strcmp (buffer, "file") == 0 || strcmp (buffer, "socket") == 0)
{
size_t size;
rc = mu_url_get_path (url, NULL, 0, &size);
if (rc)
{
mu_error (_("%s: cannot get path: %s"), urlstr, mu_strerror(rc));
return EX_CONFIG;
}
if (size > sizeof addr.s_un.sun_path - 1)
{
mu_error (_("%s: file name too long"), urlstr);
return EX_TEMPFAIL;
}
mu_url_get_path (url, addr.s_un.sun_path, sizeof addr.s_un.sun_path,
NULL);
fd = socket (PF_UNIX, SOCK_STREAM, 0);
if (fd < 0)
{
mu_error ("socket: %s", mu_strerror (errno));
return EX_TEMPFAIL;
}
addr.s_un.sun_family = AF_UNIX;
addrsize = sizeof addr.s_un;
if (reuse_lmtp_address)
{
struct stat st;
if (stat (addr.s_un.sun_path, &st))
{
if (errno != ENOENT)
{
mu_error (_("file %s exists but cannot be stat'd"),
addr.s_un.sun_path);
return EX_TEMPFAIL;
}
}
else if (!S_ISSOCK (st.st_mode))
{
mu_error (_("file %s is not a socket"),
addr.s_un.sun_path);
return EX_TEMPFAIL;
}
else
unlink (addr.s_un.sun_path);
}
}
else if (strcmp (buffer, "tcp") == 0)
{
size_t size;
long n;
struct hostent *hp;
char *path = NULL;
short port = 0;
rc = mu_url_get_port (url, &n);
if (rc)
{
mu_error (_("%s: cannot get port: %s"), urlstr, mu_strerror(rc));
return EX_CONFIG;
}
if (n == 0 || (port = n) != n)
{
mu_error (_("Port out of range: %ld"), n);
return EX_CONFIG;
}
rc = mu_url_get_host (url, NULL, 0, &size);
if (rc)
{
mu_error (_("%s: cannot get host: %s"), urlstr, mu_strerror(rc));
return EX_CONFIG;
}
path = malloc (size + 1);
if (!path)
{
mu_error (_("Not enough memory"));
return EX_TEMPFAIL;
}
mu_url_get_host (url, path, size + 1, NULL);
fd = socket (PF_INET, SOCK_STREAM, 0);
if (fd < 0)
{
mu_error ("socket: %s", mu_strerror (errno));
return EX_TEMPFAIL;
}
addr.s_in.sin_family = AF_INET;
hp = gethostbyname (path);
if (hp)
{
char **ap;
int count = 0;
addr.s_in.sin_addr.s_addr = *(unsigned long*) hp->h_addr_list[0];
for (ap = hp->h_addr_list; *ap; ap++)
count++;
if (count > 1)
mu_error (_("warning: %s has several IP addresses, using %s"),
path, inet_ntoa (addr.s_in.sin_addr));
}
else if (inet_aton (path, &addr.s_in.sin_addr) == 0)
{
mu_error ("invalid IP address: %s", path);
return EX_TEMPFAIL;
}
addr.s_in.sin_port = htons (port);
addrsize = sizeof addr.s_in;
if (reuse_lmtp_address)
setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &t, sizeof(t));
}
else
{
mu_error (_("%s: invalid scheme"), urlstr);
return EX_CONFIG;
}
saved_umask = umask (0117);
if (bind (fd, &addr.sa, addrsize) == -1)
{
mu_error ("bind: %s", strerror (errno));
close (fd);
return EXIT_FAILURE;
}
umask (saved_umask);
*pfd = fd;
return 0;
}
int
lmtp_open (int *pfd, char *urlstr)
{
mu_url_t url = NULL;
int rc;
rc = mu_url_create (&url, urlstr);
if (rc)
{
mu_error (_("%s: cannot create URL: %s"),
urlstr, mu_strerror (rc));
return EX_CONFIG;
}
rc = mu_url_parse (url);
if (rc)
{
mu_error (_("%s: error parsing URL: %s"),
urlstr, mu_strerror(rc));
return EX_CONFIG;
}
rc = lmtp_open_internal (pfd, url, urlstr);
mu_url_destroy (&url);
return rc;
}
size_t children;
static int need_cleanup = 0;
void
process_cleanup ()
{
pid_t pid;
int status;
if (need_cleanup)
{
need_cleanup = 0;
while ( (pid = waitpid (-1, &status, WNOHANG)) > 0)
--children;
}
}
RETSIGTYPE
lmtp_sigchld (int signo MU_ARG_UNUSED)
{
need_cleanup = 1;
#ifndef HAVE_SIGACTION
signal (signo, lmtp_sigchld);
#endif
}
static int lmtp_transcript;
void
lmtp_reply (FILE *fp, char *code, char *enh, char *fmt, ...)
......@@ -252,7 +37,7 @@ lmtp_reply (FILE *fp, char *code, char *enh, char *fmt, ...)
vasprintf (&str, fmt, ap);
va_end (ap);
if (mu_gocs_daemon.transcript)
if (lmtp_transcript)
{
if (enh)
mu_diag_output (MU_DIAG_INFO, "LMTP reply: %s %s %s", code, enh, str);
......@@ -697,8 +482,18 @@ getcmd (char *buf, char **sp)
return cp;
}
static char *
to_fgets (char *buf, size_t size, FILE *fp, unsigned int timeout)
{
char *p;
alarm (timeout);
p = fgets (buf, size, fp);
alarm (0);
return p;
}
int
lmtp_loop (FILE *in, FILE *out)
lmtp_loop (FILE *in, FILE *out, unsigned int timeout)
{
char buf[1024];
enum lmtp_state state = state_init;
......@@ -707,7 +502,7 @@ lmtp_loop (FILE *in, FILE *out)
setvbuf (out, NULL, _IOLBF, 0);
lmtp_reply (out, "220", NULL, "At your service");
while (fgets (buf, sizeof buf, in))
while (to_fgets (buf, sizeof buf, in, timeout))
{
if (state == state_data
&& !(buf[0] == '.'
......@@ -737,7 +532,7 @@ lmtp_loop (FILE *in, FILE *out)
trimnl (buf);
if (mu_gocs_daemon.transcript)
if (lmtp_transcript)
mu_diag_output (MU_DIAG_INFO, "LMTP recieve: %s", buf);
if (next_state != state_none)
......@@ -762,144 +557,15 @@ lmtp_loop (FILE *in, FILE *out)
}
int
check_connection (int fd, all_addr_t *addr, socklen_t addrlen)
lmtp_connection (int fd, void *data, time_t timeout, int transcript)
{
switch (addr->sa.sa_family)
{
case PF_UNIX:
mu_diag_output (MU_DIAG_INFO, _("connect from socket"));
break;
case PF_INET:
if (maidag_acl)
{
mu_acl_result_t res;
int rc = mu_acl_check_sockaddr (maidag_acl, &addr->sa, addrlen,
&res);
if (rc)
{
mu_error (_("Access from %s blocked: cannot check ACLs: %s"),
inet_ntoa (addr->s_in.sin_addr), mu_strerror (rc));
return 1;
}
switch (res)
{
case mu_acl_result_undefined:
mu_diag_output (MU_DIAG_INFO,
_("%s: undefined ACL result; access allowed"),
inet_ntoa (addr->s_in.sin_addr));
break;
case mu_acl_result_accept:
break;
case mu_acl_result_deny:
mu_error (_("Access from %s blocked."),
inet_ntoa (addr->s_in.sin_addr));
return 1;
}
}
if (!mu_tcpwrapper_access (fd))
{
mu_error (_("Access from %s blocked by tcp wrappers."),
inet_ntoa (addr->s_in.sin_addr));
return 1;
}
}
/* FIXME: TCP wrappers */
lmtp_transcript = transcript;
lmtp_loop (fdopen (fd, "r"), fdopen (fd, "w"), timeout);
return 0;
}
int
lmtp_daemon (char *urlstr)
{
int rc;
int listenfd, connfd;
all_addr_t addr;
socklen_t addrlen;
pid_t pid;
if (mu_gocs_daemon.mode == MODE_DAEMON)
{
if (daemon (0, 0) < 0)
{
mu_error (_("Failed to become a daemon"));
return EX_UNAVAILABLE;
}
}
rc = lmtp_open (&listenfd, urlstr);
if (rc)
return rc;
if (listen (listenfd, 128) == -1)
{
mu_error ("listen: %s", strerror (errno));
close (listenfd);
return EX_UNAVAILABLE;
}
#ifdef HAVE_SIGACTION
{
struct sigaction act;
act.sa_handler = lmtp_sigchld;
sigemptyset (&act.sa_mask);
act.sa_flags = 0;
sigaction (SIGCHLD, &act, NULL);
}
#else
signal (SIGCHLD, lmtp_sigchld);
#endif
for (;;)
{
process_cleanup ();
if (children > mu_gocs_daemon.maxchildren)
{
mu_error (_("too many children (%lu)"),
(unsigned long) children);
pause ();
continue;
}
addrlen = sizeof addr;
connfd = accept (listenfd, (struct sockaddr *)&addr, &addrlen);
if (connfd == -1)
{
if (errno == EINTR)
continue;
mu_error ("accept: %s", strerror (errno));
continue;
/*exit (EXIT_FAILURE);*/
}
if (check_connection (connfd, &addr, addrlen))
{
close (connfd);
continue;
}
pid = fork ();
if (pid == -1)
mu_diag_output (MU_DIAG_ERROR, "fork: %s", strerror (errno));
else if (pid == 0) /* Child. */
{
int status;
close (listenfd);
status = lmtp_loop (fdopen (connfd, "r"), fdopen (connfd, "w"));
exit (status);
}
else
{
++children;
}
close (connfd);
}
}
#define DEFAULT_URL "tcp://127.0.0.1:"
int
maidag_lmtp_server ()
{
struct group *gr = getgrnam (lmtp_group);
......@@ -916,21 +582,16 @@ maidag_lmtp_server ()
return EX_UNAVAILABLE;
}
if (lmtp_url_string)
return lmtp_daemon (lmtp_url_string);
else if (mu_gocs_daemon.mode == MODE_INTERACTIVE)
return lmtp_loop (stdin, stdout);
else
{
const char *pstr = mu_umaxtostr (0, mu_gocs_daemon.port);
char *urls = malloc (sizeof (DEFAULT_URL) + strlen (pstr));
if (!urls)
if (mu_m_server_mode (server) == MODE_DAEMON)
{
mu_error (_("Not enough memory"));
return EX_TEMPFAIL;
}
strcpy (urls, DEFAULT_URL);
strcat (urls, pstr);
return lmtp_daemon (urls);
int status;
mu_m_server_begin (server);
status = mu_m_server_run (server);
mu_m_server_end (server);
mu_m_server_destroy (&server);
if (status)
return EX_CONFIG;
}
else
return lmtp_loop (stdin, stdout, 0);
}
......
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 2007 Free Software Foundation, Inc.
Copyright (C) 2007, 2008 Free Software Foundation, Inc.
GNU Mailutils is free software; you can redistribute it and/or modify
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
identifier when logging Sieve actions */
/* For LMTP mode */
mu_m_server_t server;
int lmtp_mode;
char *lmtp_url_string;
int reuse_lmtp_address = 1;
char *lmtp_group = "mail";
mu_acl_t maidag_acl; /* ACLs for LMTP mode */
struct mu_gocs_daemon daemon_param = {
MODE_INTERACTIVE, /* Start in interactive (inetd) mode */
20, /* Default maximum number of children */
0, /* No standard port */
600, /* Idle timeout */
0, /* No transcript by default */
NULL /* No PID file by default */
};
const char *program_version = "maidag (" PACKAGE_STRING ")";
static char doc[] =
......@@ -74,9 +65,15 @@ static char args_doc[] = N_("[recipient...]");
#define STDERR_OPTION 256
#define MESSAGE_ID_HEADER_OPTION 257
#define LMTP_OPTION 258
#define FOREGROUND_OPTION 260
static struct argp_option options[] =
{
{ "foreground", FOREGROUND_OPTION, 0, 0, N_("Remain in foreground."), 0 },
{ "inetd", 'i', 0, 0, N_("Run in inetd mode"), 0 },
{ "daemon", 'd', N_("NUMBER"), OPTION_ARG_OPTIONAL,
N_("Runs in daemon mode with a maximum of NUMBER children"), 0 },
{ "from", 'f', N_("EMAIL"), 0,
N_("Specify the sender's name") },
{ NULL, 'r', NULL, OPTION_ALIAS, NULL },
......@@ -109,7 +106,6 @@ static struct argp argp = {
};
static const char *maidag_argp_capa[] = {
"daemon",
"auth",
"common",
"debug",
......@@ -174,6 +170,20 @@ parse_opt (int key, char *arg, struct argp_state *state)
switch (key)
{
case 'd':
mu_argp_node_list_new (&lst, "mode", "daemon");
if (arg)
mu_argp_node_list_new (&lst, "max-children", arg);
break;
case 'i':
mu_argp_node_list_new (&lst, "mode", "inetd");
break;
case FOREGROUND_OPTION:
mu_argp_node_list_new (&lst, "foreground", "yes");
break;
case MESSAGE_ID_HEADER_OPTION:
mu_argp_node_list_new (&lst, "message-id-header", arg);
break;
......@@ -291,7 +301,8 @@ struct mu_cfg_param maidag_cfg_param[] = {
N_("url") },
{ "reuse-address", mu_cfg_bool, &reuse_lmtp_address, 0, NULL,
N_("Reuse existing address (LMTP mode). Default is \"yes\".") },
{ "acl", mu_cfg_section, },
{ ".server", mu_cfg_section, NULL, 0, NULL,
N_("LMTP server configuration.") },
TCP_WRAPPERS_CONFIG
{ NULL }
};
......@@ -458,15 +469,21 @@ main (int argc, char *argv[])
mu_gocs_register ("sieve", mu_sieve_module_init);
mu_gocs_daemon = daemon_param;
mu_tcpwrapper_cfg_init ();
mu_acl_cfg_init ();
mu_m_server_cfg_init ();
/* Parse command line */
mu_argp_init (program_version, NULL);
mu_m_server_create (&server, "GNU maidag");
mu_m_server_set_conn (server, lmtp_connection);
mu_m_server_set_mode (server, MODE_INTERACTIVE);
mu_m_server_set_max_children (server, 20);
mu_m_server_set_timeout (server, 600);
if (mu_app_init (&argp, maidag_argp_capa, maidag_cfg_param,
argc, argv, 0, &arg_index, &maidag_acl))
argc, argv, 0, &arg_index, server))
exit (EX_CONFIG);
current_uid = getuid ();
......@@ -481,12 +498,8 @@ main (int argc, char *argv[])
openlog ("maidag", LOG_PID, log_facility);
mu_diag_get_debug (&debug);
mu_debug_set_print (debug, mu_diag_syslog_printer, NULL);
/* FIXME: this should be done automatically by cfg */
if (maidag_acl)
{
mu_acl_get_debug (maidag_acl, &debug);
mu_debug_set_print (debug, mu_debug_syslog_printer, NULL);
}
mu_debug_default_printer = mu_debug_syslog_printer;
}
argc -= arg_index;
......
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 2007 Free Software Foundation, Inc.
Copyright (C) 2007, 2008 Free Software Foundation, Inc.
GNU Mailutils is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -84,6 +84,7 @@
#include <mailutils/nls.h>
#include <mailutils/daemon.h>
#include <mailutils/acl.h>
#include <mailutils/server.h>
#include <mu_dbm.h>
#include <mu_asprintf.h>
......@@ -120,6 +121,7 @@ extern char *sender_address;
extern char *progfile_pattern;
extern char *sieve_pattern;
extern mu_m_server_t server;
extern int lmtp_mode;
extern char *lmtp_url_string;
extern int reuse_lmtp_address;
......@@ -131,6 +133,7 @@ int switch_user_id (struct mu_auth_data *auth, int user);
int maidag_stdio_delivery (int argc, char **argv);
int maidag_lmtp_server (void);
int lmtp_connection (int fd, void *data, time_t timeout, int transcript);
void mailer_err (char *fmt, ...);
void notify_biff (mu_mailbox_t mbox, char *name, size_t size);
......
......@@ -82,6 +82,7 @@ libmailutils_la_SOURCES = \
message_stream.c\
mime.c\
monitor.c\
msrv.c\
mu_auth.c\
mu_umaxtostr.h\
mu_umaxtostr.c\
......
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 2007 Free Software Foundation, Inc.
Copyright (C) 2007, 2008 Free Software Foundation, Inc.
This library is free software; you can redistribute it and/or
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)
return rc;
}
void
static void
debug_sockaddr (mu_debug_t dbg, mu_log_level_t lvl, struct sockaddr *sa)
{
switch (sa->sa_family)
{
case AF_INET:
{
struct sockaddr_in *s_in = (struct sockaddr_in *)sa;
struct sockaddr_in s_in = *(struct sockaddr_in *)sa;
s_in.sin_addr.s_addr = htonl (s_in.sin_addr.s_addr);
mu_debug_printf (dbg, lvl, "{AF_INET %s:%d}",
inet_ntoa (s_in->sin_addr), ntohs (s_in->sin_port));
inet_ntoa (s_in.sin_addr), ntohs (s_in.sin_port));
break;
}
......@@ -332,6 +333,77 @@ debug_sockaddr (mu_debug_t dbg, mu_log_level_t lvl, struct sockaddr *sa)
}
}
size_t
mu_stpcpy (char **pbuf, size_t *psize, const char *src)
{
size_t slen = strlen (src);
if (pbuf == NULL || *pbuf == NULL)
return slen;
else
{
char *buf = *pbuf;
size_t size = *psize;
if (size > slen)
size = slen;
memcpy (buf, src, size);
*psize -= size;
*pbuf += size;
if (*psize)
**pbuf = 0;
else
(*pbuf)[-1] = 0;
return size;
}
}
void
mu_sockaddr_to_str (struct sockaddr *sa, int salen,
char *bufptr, size_t buflen,
size_t *plen)
{
char buf[UINTMAX_STRSIZE_BOUND]; /* FIXME: too much */
size_t len = 0;
switch (sa->sa_family)
{
case AF_INET:
{
struct sockaddr_in s_in = *(struct sockaddr_in *)sa;
len += mu_stpcpy (&bufptr, &buflen, inet_ntoa (s_in.sin_addr));
len += mu_stpcpy (&bufptr, &buflen, ":");
len += mu_stpcpy (&bufptr, &buflen, umaxtostr (ntohs (s_in.sin_port),
buf));
break;
}
case AF_UNIX:
{
struct sockaddr_un *s_un = (struct sockaddr_un *)sa;
len += mu_stpcpy (&bufptr, &buflen, "socket ");
len += mu_stpcpy (&bufptr, &buflen, s_un->sun_path);
break;
}
default:
len += mu_stpcpy (&bufptr, &buflen, "{Unsupported family: ");
len += mu_stpcpy (&bufptr, &buflen, umaxtostr (sa->sa_family, buf));
}
if (plen)
*plen = len + 1;
}
char *
mu_sockaddr_to_astr (struct sockaddr *sa, int salen)
{
size_t size;
char *p;
mu_sockaddr_to_str (sa, salen, NULL, 0, &size);
p = malloc (size);
if (p)
mu_sockaddr_to_str (sa, salen, p, size, NULL);
return p;
}
int
_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)
mu_debug_printf (debug, MU_DEBUG_TRACE0, " match ");
debug_sockaddr (debug, MU_DEBUG_TRACE0, ent->sa);
a.s_addr = ent->netmask;
a.s_addr = htonl (a.s_addr);
mu_debug_printf (debug, MU_DEBUG_TRACE0, " netmask %s? ", inet_ntoa (a));
}
......
/* cfg_driver.c -- Main driver for Mailutils configuration files
Copyright (C) 2007 Free Software Foundation, Inc.
Copyright (C) 2007, 2008 Free Software Foundation, Inc.
GNU Mailutils is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
......@@ -163,6 +163,7 @@ dup_container (struct mu_cfg_cont **pcont)
newcont->v.section.label = oldcont->v.section.label;
newcont->v.section.parser = oldcont->v.section.parser;
newcont->v.section.target = oldcont->v.section.target;
newcont->v.section.offset = oldcont->v.section.offset;
newcont->v.section.docstring = oldcont->v.section.docstring;
newcont->v.section.children = NULL;
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,
param->ident);
abort ();
}
if (param->ident[0] == '.')
{
mu_iterator_t itr;
mu_list_get_iterator (container->v.section.children, &itr);
for (mu_iterator_first (itr);
!mu_iterator_is_done (itr);
mu_iterator_next (itr))
{
struct mu_cfg_cont *c;
mu_iterator_current (itr, (void**)&c);
mu_config_clone_container (c);
if (mu_refcount_value (c->refcount) > 1)
dup_container (&c);
switch (c->type)
{
case mu_cfg_cont_section:
c->v.section.offset += param->offset;
break;
case mu_cfg_cont_param:
container->v.param.offset += param->offset;
break;
}
mu_cfg_section_add_container (sect, c);
}
mu_iterator_destroy (&itr);
continue;
}
else
{
mu_config_clone_container (container);
if (mu_refcount_value (container->refcount) > 1)
dup_container (&container);
container->v.section.offset = param->offset;
}
}
else
{
rc = mu_config_create_container (&container, mu_cfg_cont_param);
......
/* cfg_lexer.c -- default lexer for Mailutils configuration files
Copyright (C) 2007 Free Software Foundation, Inc.
Copyright (C) 2007, 2008 Free Software Foundation, Inc.
GNU Mailutils is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
......@@ -118,7 +118,7 @@ static int
isword (int c)
{
if (mu_cfg_tie_in)
return c && c != ';';
return c && c != ';' && c != '{';
return isalnum (c) || c == '_' || c == '-' || c == '.';
}
......@@ -137,6 +137,22 @@ copy_alpha (struct lexer_data *p)
return cbuf_finish (p);
}
static char *
copy_to (struct lexer_data *p, const char *delim)
{
while (*p->curp)
{
if (strchr (delim, *p->curp))
break;
if (*p->curp == '\n')
mu_cfg_locus.line++;
cbuf_1grow (p, *p->curp);
p->curp++;
}
cbuf_1grow (p, 0);
return cbuf_finish (p);
}
static int
continuation_line_p (struct lexer_data *p, int quote)
{
......@@ -210,6 +226,15 @@ copy_string (struct lexer_data *p)
} \
while (0)
static void
rtrim (char *arg)
{
int len = strlen (arg);
while (len > 0 && strchr (" \t\n\r", arg[len-1]))
len--;
arg[len] = 0;
}
int
default_lexer (void *dp, mu_debug_t dbg)
{
......@@ -311,6 +336,7 @@ again:
tag = copy_alpha (p);
skipws (p);
if (*p->curp == '"')
{
mu_cfg_yylval.string = tag;
......@@ -321,8 +347,8 @@ again:
save_start = p->curp;
if (*p->curp != '{')
{
label = copy_alpha (p);
skipws (p);
label = copy_to (p, ";{");
rtrim (label);
}
else
label = NULL;
......
%{
/* cfg_parser.y -- general-purpose configuration file parser
Copyright (C) 2007 Free Software Foundation, Inc.
Copyright (C) 2007, 2008 Free Software Foundation, Inc.
GNU Mailutils is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
......@@ -260,8 +260,17 @@ mu_cfg_parse (mu_cfg_tree_t **ptree,
_mu_cfg_debug = debug;
else
{
mu_log_level_t level;
mu_debug_create (&_mu_cfg_debug, NULL);
mu_debug_set_print (_mu_cfg_debug, _cfg_default_printer, NULL);
level = mu_global_debug_level ("config");
if (level)
{
mu_debug_set_level (_mu_cfg_debug, level);
if (level & MU_DEBUG_LEVEL_MASK (MU_DEBUG_TRACE7))
yydebug = 1;
}
}
_mu_cfg_alloc = palloc ? palloc : malloc;
_mu_cfg_free = pfree ? pfree : free;
......@@ -1006,14 +1015,20 @@ _scan_tree_helper (const mu_cfg_node_t *node, void *data)
sec->target = (char*)sdata->list->sec->target + sec->offset;
else if (sdata->target)
sec->target = (char*)sdata->target + sec->offset;
if (sec->parser &&
sec->parser (mu_cfg_section_start, node,
if (sec->parser)
{
mu_debug_set_locus (sdata->tree->debug,
node->locus.file ?
node->locus.file : _("unknown file"),
node->locus.line);
if (sec->parser (mu_cfg_section_start, node,
sec->label, &sec->target,
sdata->call_data, sdata->tree))
{
sdata->error++;
return MU_CFG_ITER_SKIP;
}
}
push_section(sdata, sec);
break;
......@@ -1059,15 +1074,26 @@ int
mu_cfg_scan_tree (mu_cfg_tree_t *tree, struct mu_cfg_section *sections,
void *target, void *data)
{
mu_debug_t debug = NULL;
struct scan_tree_data dat;
dat.tree = tree;
dat.list = NULL;
dat.error = 0;
dat.call_data = data;
dat.target = target;
if (!tree->debug)
{
mu_diag_get_debug (&debug);
tree->debug = debug;
}
if (push_section (&dat, sections))
return 1;
mu_cfg_preorder (tree->node, _scan_tree_helper, _scan_tree_end_helper, &dat);
if (debug)
{
mu_debug_set_locus (debug, NULL, 0);
tree->debug = NULL;
}
pop_section (&dat);
return dat.error;
}
......
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 2004, 2005, 2007 Free Software Foundation, Inc.
Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
......@@ -29,6 +29,7 @@
#include <string.h>
#include <mailutils/daemon.h>
#include <mailutils/errno.h>
#include <mu_umaxtostr.h>
static char *pidfile;
......@@ -42,7 +43,7 @@ mu_daemon_create_pidfile (const char *filename)
if (filename[0] != '/')
{
return 1; /* failure */
return EINVAL; /* failure */
}
if (pidfile)
......@@ -55,7 +56,7 @@ mu_daemon_create_pidfile (const char *filename)
if ((fd = open (pidfile, O_WRONLY | O_CREAT
| O_TRUNC | O_EXCL, 0644)) == -1)
{
return 2; /* failure */
return errno; /* failure */
}
pid_string = mu_umaxtostr (0, current_pid);
......
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 1999, 2000, 2001, 2004, 2005,
2007 Free Software Foundation, Inc.
2007, 2008 Free Software Foundation, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
......@@ -41,7 +41,7 @@ mu_debug_create (mu_debug_t *pdebug, void *owner)
debug = calloc (sizeof (*debug), 1);
if (debug == NULL)
return ENOMEM;
debug->printer = mu_debug_default_printer;
debug->printer = NULL;
debug->owner = owner;
*pdebug = debug;
return 0;
......@@ -146,10 +146,13 @@ int
mu_debug_vprintf (mu_debug_t debug, mu_log_level_t level,
const char *format, va_list ap)
{
mu_debug_printer_fp printer;
if (debug == NULL || format == NULL)
return EINVAL;
if (debug->printer)
printer = debug->printer ? debug->printer : mu_debug_default_printer;
if (printer)
{
mu_off_t len;
mu_transport_t tbuf;
......@@ -186,7 +189,7 @@ mu_debug_vprintf (mu_debug_t debug, mu_log_level_t level,
{
int c = *++p;
*p = 0;
debug->printer (debug->data, level, ptr);
printer (debug->data, level, ptr);
*p = c;
ptr = p;
nseg++;
......@@ -252,7 +255,7 @@ mu_debug_check_level (mu_debug_t debug, mu_log_level_t level)
{
if (!debug)
return 0;
return debug->level & level;
return debug->level & MU_DEBUG_LEVEL_MASK (level);
}
int
......
......@@ -90,7 +90,7 @@ mu_folder_create_from_record (mu_folder_t *pfolder, const char *name,
status = mu_url_parse (url);
if (status)
{
mu_url_destroy (url);
mu_url_destroy (&url);
return status;
}
mu_record_get_url (record, &u_init);
......@@ -99,7 +99,7 @@ mu_folder_create_from_record (mu_folder_t *pfolder, const char *name,
status = u_init (url);
if (status)
{
mu_url_destroy (url);
mu_url_destroy (&url);
return status;
}
}
......
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 2008 Free Software Foundation, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; If not, see
<http://www.gnu.org/licenses/>. */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <syslog.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/stat.h>
#include <ctype.h>
#include <mailutils/server.h>
#include <mailutils/error.h>
#include <mailutils/errno.h>
#include <mailutils/cfg.h>
#include <mailutils/nls.h>
#include <mailutils/daemon.h>
#include <mailutils/acl.h>
typedef RETSIGTYPE (*mu_sig_handler_t) (int);
static mu_sig_handler_t
set_signal (int sig, mu_sig_handler_t handler)
{
#ifdef HAVE_SIGACTION
{
struct sigaction act, oldact;
act.sa_handler = handler;
sigemptyset (&act.sa_mask);
act.sa_flags = 0;
sigaction (sig, &act, &oldact);
return oldact.sa_handler;
}
#else
return signal (sig, handler);
#endif
}
#ifndef NSIG
# define NSIG 64
#endif
struct _mu_m_server
{
char *ident;
mu_server_t server;
mu_list_t srvlist;
mu_m_server_conn_fp conn;
void *data;
int mode;
int foreground;
size_t max_children;
char *pidfile;
unsigned short defport;
time_t timeout;
mu_acl_t acl;
sigset_t sigmask;
mu_sig_handler_t sigtab[NSIG];
};
static int need_cleanup = 0;
static int stop = 0;
static size_t children;
static int
mu_m_server_idle (void *server_data MU_ARG_UNUSED)
{
pid_t pid;
int status;
if (need_cleanup)
{
need_cleanup = 0;
while ( (pid = waitpid (-1, &status, WNOHANG)) > 0)
{
--children;
if (WIFEXITED (status))
{
int prio = MU_DIAG_INFO;
status = WEXITSTATUS (status);
if (status == 0)
prio = MU_DIAG_DEBUG;
mu_diag_output (prio, "process %lu finished with code %d",
(unsigned long) pid,
status);
}
else if (WIFSIGNALED (status))
mu_diag_output (MU_DIAG_ERR, "process %lu terminated on signal %d",
(unsigned long) pid,
WTERMSIG (status));
else
mu_diag_output (MU_DIAG_ERR,
"process %lu terminated (cause unknown)",
(unsigned long) pid);
}
}
return stop;
}
static RETSIGTYPE
m_srv_signal (int signo)
{
switch (signo)
{
case SIGCHLD:
need_cleanup = 1;
break;
default:
stop = 1;
break;
}
#ifndef HAVE_SIGACTION
signal (signo, m_srv_sigchld);
#endif
}
void
mu_m_server_create (mu_m_server_t *psrv, const char *ident)
{
mu_m_server_t srv = calloc (1, sizeof *srv);
if (!srv)
{
mu_error ("%s", mu_strerror (ENOMEM));
exit (1);
}
if (ident)
{
srv->ident = strdup (ident);
if (!srv->ident)
{
mu_error ("%s", mu_strerror (ENOMEM));
exit (1);
}
}
MU_ASSERT (mu_server_create (&srv->server));
mu_server_set_idle (srv->server, mu_m_server_idle);
sigemptyset (&srv->sigmask);
sigaddset (&srv->sigmask, SIGCHLD);
sigaddset (&srv->sigmask, SIGINT);
sigaddset (&srv->sigmask, SIGTERM);
sigaddset (&srv->sigmask, SIGQUIT);
sigaddset (&srv->sigmask, SIGHUP);
*psrv = srv;
}
void
mu_m_server_set_sigset (mu_m_server_t srv, sigset_t *sigset)
{
srv->sigmask = *sigset;
sigaddset (&srv->sigmask, SIGCHLD);
}
void
mu_m_server_get_sigset (mu_m_server_t srv, sigset_t *sigset)
{
*sigset = srv->sigmask;
}
void
mu_m_server_set_mode (mu_m_server_t srv, int mode)
{
srv->mode = mode;
}
void
mu_m_server_set_conn (mu_m_server_t srv, mu_m_server_conn_fp conn)
{
srv->conn = conn;
}
void
mu_m_server_set_data (mu_m_server_t srv, void *data)
{
srv->data = data;
}
void
mu_m_server_set_max_children (mu_m_server_t srv, size_t num)
{
srv->max_children = num;
}
int
mu_m_server_set_pidfile (mu_m_server_t srv, const char *pidfile)
{
free (srv->pidfile);
srv->pidfile = strdup (pidfile);
return srv->pidfile ? 0 : errno;
}
void
mu_m_server_set_default_port (mu_m_server_t srv, int port)
{
srv->defport = port;
}
void
mu_m_server_set_timeout (mu_m_server_t srv, time_t t)
{
srv->timeout = t;
}
int
mu_m_server_mode (mu_m_server_t srv)
{
return srv->mode;
}
time_t
mu_m_server_timeout (mu_m_server_t srv)
{
return srv->timeout;
}
struct m_srv_config
{
mu_m_server_t msrv;
mu_tcp_server_t tcpsrv;
mu_acl_t acl;
int single_process;
int transcript;
time_t timeout;
};
void
m_srv_config_free (void *data)
{
struct m_srv_config *pconf = data;
/* FIXME */
free (pconf);
}
static int m_srv_conn (int fd, struct sockaddr *sa, int salen,
void *server_data, void *call_data,
mu_tcp_server_t srv);
static struct m_srv_config *
add_server (mu_m_server_t msrv, struct sockaddr *s, int slen)
{
mu_tcp_server_t tcpsrv;
struct m_srv_config *pconf;
MU_ASSERT (mu_tcp_server_create (&tcpsrv, s, slen));
MU_ASSERT (mu_tcp_server_set_conn (tcpsrv, m_srv_conn));
pconf = calloc (1, sizeof (*pconf));
if (!pconf)
{
mu_error ("%s", mu_strerror (ENOMEM));
exit (1);
}
pconf->msrv = msrv;
pconf->tcpsrv = tcpsrv;
pconf->single_process = 0;
pconf->timeout = msrv->timeout;
MU_ASSERT (mu_tcp_server_set_data (tcpsrv, pconf, m_srv_config_free));
if (!msrv->srvlist)
MU_ASSERT (mu_list_create (&msrv->srvlist));
MU_ASSERT (mu_list_append (msrv->srvlist, tcpsrv));
return pconf;
}
void
mu_m_server_configured_count (mu_m_server_t msrv, size_t count)
{
mu_list_count (msrv->srvlist, &count);
}
void
mu_m_server_begin (mu_m_server_t msrv)
{
int i, rc;
size_t count = 0;
mu_list_count (msrv->srvlist, &count);
if (count == 0 && msrv->defport)
{
/* Add default server */
struct sockaddr_in s;
s.sin_addr.s_addr = htonl (INADDR_ANY);
s.sin_port = htons (msrv->defport);
add_server (msrv, (struct sockaddr *)&s, sizeof s);
}
if (!msrv->foreground)
{
/* Become a daemon. Take care to close inherited fds and to hold
first three one, in, out, err */
if (daemon (0, 0) < 0)
{
mu_error (_("Failed to become a daemon: %s"), mu_strerror (errno));
exit (EXIT_FAILURE);
}
}
if (msrv->pidfile)
switch (rc = mu_daemon_create_pidfile (msrv->pidfile))
{
case EINVAL:
mu_error (_("%s: Invalid name for a pidfile"), msrv->pidfile);
break;
default:
mu_error (_("cannot create pidfile `%s': %s"), msrv->pidfile,
mu_strerror (rc));
}
for (i = 0; i < NSIG; i++)
if (sigismember (&msrv->sigmask, i))
msrv->sigtab[i] = set_signal (i, m_srv_signal);
}
void
mu_m_server_end (mu_m_server_t msrv)
{
int i;
for (i = 0; i < NSIG; i++)
if (sigismember (&msrv->sigmask, i))
set_signal (i, msrv->sigtab[i]);
}
void
mu_m_server_destroy (mu_m_server_t *pmsrv)
{
mu_m_server_t msrv = *pmsrv;
mu_server_destroy (&msrv->server);
/* FIXME: Send processes the TERM signal */
free (msrv->ident);
free (msrv);
*pmsrv = NULL;
}
static int
tcp_conn_handler (int fd, void *conn_data, void *server_data)
{
mu_tcp_server_t tcpsrv = (mu_tcp_server_t) conn_data;
int rc = mu_tcp_server_accept (tcpsrv, server_data);
if (rc && rc != EINTR)
{
mu_tcp_server_shutdown (tcpsrv);
return MU_SERVER_CLOSE_CONN;
}
return stop ? MU_SERVER_SHUTDOWN : MU_SERVER_SUCCESS;
}
static void
tcp_conn_free (void *conn_data, void *server_data)
{
mu_tcp_server_t tcpsrv = (mu_tcp_server_t) conn_data;
mu_tcp_server_destroy (&tcpsrv);
}
static int
_open_conn (void *item, void *data)
{
union
{
struct sockaddr sa;
char pad[512];
}
addr;
int addrlen = sizeof addr;
char *p;
mu_tcp_server_t tcpsrv = item;
mu_m_server_t msrv = data;
int rc = mu_tcp_server_open (tcpsrv);
if (rc)
{
mu_tcp_server_get_sockaddr (tcpsrv, &addr.sa, &addrlen);
p = mu_sockaddr_to_astr (&addr.sa, addrlen);
mu_error (_("Cannot open connection on %s: %s"), p, mu_strerror (rc));
free (p);
return 0;
}
rc = mu_server_add_connection (msrv->server,
mu_tcp_server_get_fd (tcpsrv),
tcpsrv,
tcp_conn_handler, tcp_conn_free);
if (rc)
{
mu_tcp_server_get_sockaddr (tcpsrv, &addr.sa, &addrlen);
p = mu_sockaddr_to_astr (&addr.sa, addrlen);
mu_error (_("Cannot add connection %s: %s"), p, mu_strerror (rc));
free (p);
mu_tcp_server_shutdown (tcpsrv);
mu_tcp_server_destroy (&tcpsrv);
}
return 0;
}
int
mu_m_server_run (mu_m_server_t msrv)
{
int rc;
size_t count;
mode_t saved_umask = umask (0117);
mu_list_do (msrv->srvlist, _open_conn, msrv);
umask (saved_umask);
mu_list_destroy (&msrv->srvlist);
MU_ASSERT (mu_server_count (msrv->server, &count));
if (count == 0)
{
mu_error (_("No servers configured: exiting"));
exit (1);
}
if (msrv->ident)
mu_diag_output (MU_DIAG_INFO, _("%s started"), msrv->ident);
rc = mu_server_run (msrv->server);
if (msrv->ident)
mu_diag_output (MU_DIAG_INFO, _("%s terminated"), msrv->ident);
return rc;
}
static int
check_global_acl (mu_m_server_t msrv, struct sockaddr *s, int salen)
{
if (msrv->acl)
{
mu_acl_result_t res;
int rc = mu_acl_check_sockaddr (msrv->acl, s, salen, &res);
if (rc)
{
char *p = mu_sockaddr_to_astr (s, salen);
mu_error (_("Access from %s blocked: cannot check ACLs: %s"),
p, mu_strerror (rc));
free (p);
return 1;
}
switch (res)
{
case mu_acl_result_undefined:
{
char *p = mu_sockaddr_to_astr (s, salen);
mu_diag_output (MU_DIAG_INFO,
_("%s: undefined ACL result; access allowed"),
p);
free (p);
}
break;
case mu_acl_result_accept:
break;
case mu_acl_result_deny:
{
char *p = mu_sockaddr_to_astr (s, salen);
mu_error (_("Access from %s blocked."), p);
free (p);
return 1;
}
}
}
return 0;
}
int
m_srv_conn (int fd, struct sockaddr *sa, int salen,
void *server_data, void *call_data,
mu_tcp_server_t srv)
{
int status;
struct m_srv_config *pconf = server_data;
if (check_global_acl (pconf->msrv, sa, salen))
return 0;
if (!pconf->single_process)
{
pid_t pid;
if (mu_m_server_idle (server_data))
return MU_SERVER_SHUTDOWN;
if (children >= pconf->msrv->max_children)
{
mu_diag_output (MU_DIAG_ERROR, _("too many children (%lu)"),
(unsigned long) children);
pause ();
return 0;
}
pid = fork ();
if (pid == -1)
mu_diag_output (MU_DIAG_ERROR, "fork: %s", strerror (errno));
else if (pid == 0) /* Child. */
{
mu_tcp_server_shutdown (srv);
status = pconf->msrv->conn (fd, pconf->msrv->data,
pconf->timeout, pconf->transcript);
closelog ();
exit (status);
}
else
{
children++;
}
}
else
pconf->msrv->conn (fd, pconf->msrv->data,
pconf->timeout, pconf->transcript);
return 0;
}
unsigned short
get_port (mu_debug_t debug, char *p)
{
if (p)
{
char *q;
unsigned long n = strtoul (p, &q, 0);
if (*q == 0)
{
if (n > USHRT_MAX)
{
mu_debug_printf (debug, MU_DEBUG_ERROR,
_("invalid port number: %s\n"), p);
return 1;
}
return htons (n);
}
else
{
struct servent *sp = getservbyname (p, "tcp");
if (!sp)
return 0;
return sp->s_port;
}
}
return 0;
}
static int
get_family (char **pstr, sa_family_t *pfamily)
{
static struct family_tab
{
int len;
char *pfx;
int family;
} ftab[] = {
#define S(s,f) { sizeof (#s":") - 1, #s":", f }
S (file, AF_UNIX),
S (unix, AF_UNIX),
S (local, AF_UNIX),
S (socket, AF_UNIX),
S (inet, AF_INET),
S (tcp, AF_INET),
#undef S
{ 0 }
};
struct family_tab *fp;
char *str = *pstr;
int len = strlen (str);
for (fp = ftab; fp->len; fp++)
{
if (len > fp->len && memcmp (str, fp->pfx, fp->len) == 0)
{
str += fp->len;
if (str[0] == '/' && str[1] == '/')
str += 2;
*pstr = str;
*pfamily = fp->family;
return 0;
}
}
return 1;
}
static int
is_ip_addr (const char *arg)
{
int dot_count;
int digit_count;
dot_count = 0;
digit_count = 0;
for (; *arg != 0 && *arg != ':'; arg++)
{
if (*arg == '.')
{
if (++dot_count > 3)
break;
digit_count = 0;
}
else if (!(isdigit (*arg) && ++digit_count <= 3))
return 0;
}
return dot_count == 3;
}
static int
server_block_begin (mu_debug_t debug, char *arg, mu_m_server_t msrv,
void **pdata)
{
char *p;
union
{
struct sockaddr s_sa;
struct sockaddr_in s_in;
struct sockaddr_un s_un;
}
s;
int salen = sizeof s.s_in;
s.s_sa.sa_family = AF_INET;
if (!arg)
{
s.s_in.sin_addr.s_addr = htonl (INADDR_ANY);
s.s_in.sin_port = htons (msrv->defport);
}
else
{
unsigned short n;
int len;
if (!is_ip_addr (arg) && get_family (&arg, &s.s_sa.sa_family))
{
mu_debug_printf (debug, MU_DEBUG_ERROR, _("invalid family\n"));
return 1;
}
switch (s.s_in.sin_family)
{
case AF_INET:
if ((n = get_port (debug, arg)))
{
s.s_in.sin_addr.s_addr = htonl (INADDR_ANY);
s.s_in.sin_port = htons (n);
}
else
{
p = strchr (arg, ':');
if (p)
*p++ = 0;
if (inet_aton (arg, &s.s_in.sin_addr) == 0)
{
struct hostent *hp = gethostbyname (arg);
if (hp)
s.s_in.sin_addr.s_addr = *(unsigned long *)hp->h_addr;
else
{
mu_debug_printf (debug, MU_DEBUG_ERROR,
_("invalid IP address: %s\n"), arg);
return 1;
}
}
if (p)
{
n = get_port (debug, p);
if (!n)
{
mu_debug_printf (debug, MU_DEBUG_ERROR,
_("invalid port number: %s\n"), p);
return 1;
}
s.s_in.sin_port = n;
}
else if (msrv->defport)
s.s_in.sin_port = htons (msrv->defport);
else
{
mu_debug_printf (debug, MU_DEBUG_ERROR,
_("missing port number\n"));
return 1;
}
}
break;
case AF_UNIX:
salen = sizeof s.s_un;
len = strlen (arg);
if (len > sizeof s.s_un.sun_path - 1)
{
mu_error (_("%s: file name too long"), arg);
return 1;
}
strcpy (s.s_un.sun_path, arg);
break;
}
}
*pdata = add_server (msrv, &s.s_sa, salen);
return 0;
}
static int
server_section_parser (enum mu_cfg_section_stage stage,
const mu_cfg_node_t *node,
const char *section_label, void **section_data,
void *call_data,
mu_cfg_tree_t *tree)
{
switch (stage)
{
case mu_cfg_section_start:
{
/* FIXME: should not modify 2nd arg, or it should not be const */
return server_block_begin (tree->debug, node->tag_label,
*section_data, section_data);
}
break;
case mu_cfg_section_end:
{
struct m_srv_config *pconf = *section_data;
if (pconf->acl)
mu_tcp_server_set_acl (pconf->tcpsrv, pconf->acl);
}
break;
}
return 0;
}
static int
_cb_daemon_mode (mu_debug_t debug, void *data, char *arg)
{
int *pmode = data;
if (strcmp (arg, "inetd") == 0
|| strcmp (arg, "interactive") == 0)
*pmode = MODE_INTERACTIVE;
else if (strcmp (arg, "daemon") == 0)
*pmode = MODE_DAEMON;
else
{
mu_cfg_format_error (debug, MU_DEBUG_ERROR, _("unknown daemon mode"));
return 1;
}
return 0;
}
static struct mu_cfg_param dot_server_cfg_param[] = {
{ "max-children", mu_cfg_size,
NULL, mu_offsetof (struct _mu_m_server,max_children), NULL,
N_("Maximum number of children processes to run simultaneously.") },
{ "mode", mu_cfg_callback,
NULL, mu_offsetof (struct _mu_m_server,mode), _cb_daemon_mode,
N_("Set daemon mode (either inetd (or interactive) or daemon)."),
N_("mode") },
{ "foreground", mu_cfg_bool,
NULL, mu_offsetof (struct _mu_m_server, foreground), NULL,
N_("Run in foreground.") },
{ "pidfile", mu_cfg_string,
NULL, mu_offsetof (struct _mu_m_server,pidfile), NULL,
N_("Store PID of the master process in this file."),
N_("file") },
{ "port", mu_cfg_ushort,
NULL, mu_offsetof (struct _mu_m_server,defport), NULL,
N_("Default port number.") },
{ "timeout", mu_cfg_time,
NULL, mu_offsetof (struct _mu_m_server,timeout), NULL,
N_("Set idle timeout.") },
{ "server", mu_cfg_section, NULL, 0, NULL,
N_("Server configuration.") },
{ "acl", mu_cfg_section, NULL, mu_offsetof (struct _mu_m_server,acl), NULL,
N_("Per-server access control list") },
{ NULL }
};
static struct mu_cfg_param server_cfg_param[] = {
{ "single-process", mu_cfg_bool,
NULL, mu_offsetof (struct m_srv_config, single_process), NULL,
N_("Run this server in foreground.") },
{ "transcript", mu_cfg_bool,
NULL, mu_offsetof (struct m_srv_config, transcript), NULL,
N_("Log the session transcript.") },
{ "timeout", mu_cfg_time,
NULL, mu_offsetof (struct m_srv_config, timeout), NULL,
N_("Set idle timeout.") },
{ "acl", mu_cfg_section,
NULL, mu_offsetof (struct m_srv_config, acl), NULL,
N_("Global access control list.") },
{ NULL }
};
void
mu_m_server_cfg_init ()
{
struct mu_cfg_section *section;
if (mu_create_canned_section ("server", &section) == 0)
{
section->parser = server_section_parser;
section->label = N_("ipaddr[:port]");
mu_cfg_section_add_params (section, server_cfg_param);
}
if (mu_create_canned_section (".server", &section) == 0)
{
mu_cfg_section_add_params (section, dot_server_cfg_param);
}
}
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 2007 Free Software Foundation, Inc.
Copyright (C) 2007, 2008 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify it
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)
{
int len = strlen (buf);
if (len > 0 && buf[len-1] == '\n')
{
len--;
if (len > 0 && buf[len-1] == '\r')
len--;
}
syslog (mu_diag_level_to_syslog (level), "%-.*s", len, buf);
return 0;
}
......
......@@ -21,7 +21,9 @@
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <sys/un.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
......@@ -31,12 +33,14 @@
#include <mailutils/debug.h>
#include <mailutils/diag.h>
#include <mailutils/errno.h>
#include <mailutils/nls.h>
struct _mu_tcp_server
{
char *ident;
struct sockaddr_in addr;
struct sockaddr *addr;
int addrlen;
int backlog;
int fd;
mu_debug_t debug;
......@@ -50,8 +54,8 @@ struct _mu_tcp_server
#define IDENTSTR(s) ((s)->ident ? (s)->ident : "default")
int
mu_tcp_server_create (mu_tcp_server_t *psrv,
struct sockaddr_in *addr)
mu_tcp_server_create (mu_tcp_server_t *psrv, struct sockaddr *addr,
int addrlen)
{
struct _mu_tcp_server *srv;
mu_log_level_t level;
......@@ -59,8 +63,15 @@ mu_tcp_server_create (mu_tcp_server_t *psrv,
srv = calloc (1, sizeof *srv);
if (!srv)
return ENOMEM;
srv->addr = *addr;
level = mu_global_debug_level ("mailbox");
srv->addr = calloc (1, addrlen);
if (!srv->addr)
{
free (srv);
return ENOMEM;
}
memcpy (srv->addr, addr, addrlen);
srv->addrlen = addrlen;
level = mu_global_debug_level ("tcp_server");
if (level)
{
mu_debug_create (&srv->debug, NULL);
......@@ -84,6 +95,7 @@ mu_tcp_server_destroy (mu_tcp_server_t *psrv)
if (srv->f_free)
srv->f_free (srv->data);
close (srv->fd);
free (srv->addr);
free (srv->ident);
free (srv);
*psrv = NULL;
......@@ -169,20 +181,40 @@ mu_tcp_server_set_data (mu_tcp_server_t srv,
return 0;
}
static int
family_to_proto (int family)
{
switch (family)
{
case AF_UNIX:
return PF_UNIX;
case AF_INET:
return PF_INET;
default:
abort ();
}
}
int
mu_tcp_server_open (mu_tcp_server_t srv)
{
int fd;
int t;
if (!srv || srv->fd != -1)
return EINVAL;
MU_DEBUG3 (srv->debug, MU_DEBUG_TRACE0,
"opening server \"%s\" %s:%d\n", IDENTSTR (srv),
inet_ntoa (srv->addr.sin_addr), ntohs (srv->addr.sin_port));
if (mu_debug_check_level (srv->debug, MU_DEBUG_TRACE0))
{
char *p = mu_sockaddr_to_astr (srv->addr, srv->addrlen);
__MU_DEBUG2 (srv->debug, MU_DEBUG_TRACE0,
"opening server \"%s\" %s\n", IDENTSTR (srv),
p);
free (p);
}
fd = socket (PF_INET, SOCK_STREAM, 0);
fd = socket (family_to_proto (srv->addr->sa_family), SOCK_STREAM, 0);
if (fd == -1)
{
MU_DEBUG2 (srv->debug, MU_DEBUG_ERROR,
......@@ -190,10 +222,52 @@ mu_tcp_server_open (mu_tcp_server_t srv)
return errno;
}
switch (srv->addr->sa_family)
{
case AF_UNIX:
{
struct stat st;
struct sockaddr_un *s_un = (struct sockaddr_un *) srv->addr;
if (stat (s_un->sun_path, &st))
{
if (errno != ENOENT)
{
MU_DEBUG3 (srv->debug, MU_DEBUG_ERROR,
_("%s: file %s exists but cannot be stat'd: %s"),
IDENTSTR (srv),
s_un->sun_path,
mu_strerror (errno));
return EAGAIN;
}
}
else if (!S_ISSOCK (st.st_mode))
{
MU_DEBUG2 (srv->debug, MU_DEBUG_ERROR,
_("%s: file %s is not a socket"),
IDENTSTR (srv), s_un->sun_path);
return EAGAIN;
}
else if (unlink (s_un->sun_path))
{
MU_DEBUG3 (srv->debug, MU_DEBUG_ERROR,
_("%s: cannot unlink file %s: %s"),
IDENTSTR (srv), s_un->sun_path, mu_strerror (errno));
return EAGAIN;
}
}
break;
case AF_INET:
{
int t;
t = 1;
setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &t, sizeof (t));
}
}
if (bind (fd, (struct sockaddr *) &srv->addr, sizeof (srv->addr)) == -1)
if (bind (fd, srv->addr, srv->addrlen) == -1)
{
MU_DEBUG2 (srv->debug, MU_DEBUG_ERROR,
"%s: bind: %s\n", IDENTSTR (srv), mu_strerror (errno));
......@@ -218,10 +292,14 @@ mu_tcp_server_shutdown (mu_tcp_server_t srv)
{
if (!srv || srv->fd != -1)
return EINVAL;
MU_DEBUG4 (srv->debug, MU_DEBUG_TRACE0,
"closing server \"%s\" %s:%d, fd %d\n", IDENTSTR (srv),
inet_ntoa (srv->addr.sin_addr), ntohs (srv->addr.sin_port),
srv->fd);
if (mu_debug_check_level (srv->debug, MU_DEBUG_TRACE0))
{
char *p = mu_sockaddr_to_astr (srv->addr, srv->addrlen);
__MU_DEBUG2 (srv->debug, MU_DEBUG_TRACE0,
"closing server \"%s\" %s\n", IDENTSTR (srv),
p);
free (p);
}
close (srv->fd);
return 0;
}
......@@ -231,13 +309,18 @@ mu_tcp_server_accept (mu_tcp_server_t srv, void *call_data)
{
int rc;
int connfd;
struct sockaddr_in client;
union
{
struct sockaddr sa;
char buffer[512];
} client;
socklen_t size = sizeof (client);
if (!srv || srv->fd == -1)
return EINVAL;
connfd = accept (srv->fd, (struct sockaddr *) &client, &size);
connfd = accept (srv->fd, &client.sa, &size);
if (connfd == -1)
{
int ec = errno;
......@@ -252,26 +335,26 @@ mu_tcp_server_accept (mu_tcp_server_t srv, void *call_data)
if (srv->acl)
{
mu_acl_result_t res;
int rc = mu_acl_check_sockaddr (srv->acl, (struct sockaddr *) &client,
size, &res);
int rc = mu_acl_check_sockaddr (srv->acl, &client.sa, size, &res);
if (rc)
MU_DEBUG2 (srv->debug, MU_DEBUG_ERROR,
"%s: mu_acl_check_sockaddr: %s\n",
IDENTSTR (srv), strerror (rc));
if (res == mu_acl_result_deny)
{
mu_diag_output (MU_DIAG_INFO, "Denying connection from %s:%d",
inet_ntoa (client.sin_addr),
ntohs (client.sin_port));
char *p = mu_sockaddr_to_astr (srv->addr, srv->addrlen);
mu_diag_output (MU_DIAG_INFO, "Denying connection from %s", p);
free (p);
close (connfd);
return 0;
}
}
rc = srv->f_conn (connfd, &client, srv->data, call_data, srv);
rc = srv->f_conn (connfd, &client.sa, size, srv->data, call_data, srv);
if (rc)
mu_tcp_server_shutdown (srv);
close (connfd);
return 0;
return rc;
}
int
......@@ -298,11 +381,22 @@ mu_tcp_server_get_fd (mu_tcp_server_t srv)
}
int
mu_tcp_server_get_sockaddr (mu_tcp_server_t srv, struct sockaddr_in *s)
mu_tcp_server_get_sockaddr (mu_tcp_server_t srv, struct sockaddr *s, int *size)
{
int len;
if (!srv || !s)
return EINVAL;
memcpy (s, &srv->addr, sizeof (*s));
if (s == 0)
len = srv->addrlen;
else
{
len = *size;
if (len < srv->addrlen)
len = srv->addrlen;
memcpy (s, srv->addr, len);
}
*size = len;
return 0;
}
......
......@@ -383,7 +383,7 @@ main (int argc, char *argv[])
tickets = mu_tilde_expansion ("~/.tickets", "/", NULL);
tickets_default = 1;
debug_level = MU_DEBUG_ERROR;
debug_level = MU_DEBUG_LEVEL_MASK (MU_DEBUG_ERROR);
log_facility = 0;
if (mu_app_init (&argp, sieve_argp_capa, sieve_cfg_param,
......