summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2011-01-15 14:48:06 +0200
committerSergey Poznyakoff <gray@gnu.org.ua>2011-01-15 14:48:06 +0200
commit18de516a00c01a4262310f09a1ac8586e97f8a1a (patch)
tree9598033a422818939e569f13fe4666de07b5aa7e
parentc7376cec212fc20f39388a216f29661975b109cf (diff)
downloadmailutils-18de516a00c01a4262310f09a1ac8586e97f8a1a.tar.gz
mailutils-18de516a00c01a4262310f09a1ac8586e97f8a1a.tar.bz2
imap4d: redo signal handling
Previously implemented way of signal handling was unsafe because of the use of unsafe functions in signal handlers. It also allowed for recursive invocations of MU calls not supposed to handle recursion (such as mu_mailbox_expunge, for example). This changeset fixes it. * imap4d/imap4d.c (imap4d_child_signal_setup): Change signal set. (imap4d_mainloop): Set a jump point for signal handling. Restore default handling for SIGILL, SIGBUS, SIGFPE, SIGSEGV, SIGSTOP. (master_jmp): New variable. (imap4d_master_signal): New function. (main): Redo signal handling. * imap4d/imap4d.h (child_jmp): New extern. (imap4d_enter_critical,imap4d_leave_critical): New protos. * imap4d/signal.c (imap4d_master_signal): Move to imap4d.c (imap4d_enter_critical,imap4d_leave_critical): New functions. (imap4d_child_signal): Rewrite. * imap4d/append.c: Protect critical sections. * imap4d/bye.c: Likewise. * imap4d/close.c: Likewise. * imap4d/copy.c: Likewise. * imap4d/delete.c: Likewise. * imap4d/expunge.c: Likewise. * imap4d/rename.c: Likewise. * imap4d/select.c: Likewise. * imap4d/status.c: Likewise. * scheme/Makefile.am (sievemod_DATA): Add guimb.scmi.
-rw-r--r--imap4d/append.c6
-rw-r--r--imap4d/bye.c170
-rw-r--r--imap4d/close.c4
-rw-r--r--imap4d/copy.c6
-rw-r--r--imap4d/delete.c2
-rw-r--r--imap4d/expunge.c4
-rw-r--r--imap4d/imap4d.c71
-rw-r--r--imap4d/imap4d.h4
-rw-r--r--imap4d/rename.c5
-rw-r--r--imap4d/select.c2
-rw-r--r--imap4d/signal.c61
-rw-r--r--imap4d/status.c2
-rw-r--r--scheme/Makefile.am3
13 files changed, 211 insertions, 129 deletions
diff --git a/imap4d/append.c b/imap4d/append.c
index 091602d02..003d8be6a 100644
--- a/imap4d/append.c
+++ b/imap4d/append.c
@@ -124,7 +124,8 @@ imap4d_append0 (mu_mailbox_t mbox, int flags, char *date_time, char *text,
mu_message_destroy (&msg, &tm);
return 1;
}
-
+
+ imap4d_enter_critical ();
rc = mu_mailbox_append_message (mbox, msg);
if (rc == 0)
{
@@ -140,7 +141,8 @@ imap4d_append0 (mu_mailbox_t mbox, int flags, char *date_time, char *text,
/* FIXME: If not INBOX */
quota_update (size);
}
-
+ imap4d_leave_critical ();
+
mu_message_destroy (&msg, &tm);
return rc;
}
diff --git a/imap4d/bye.c b/imap4d/bye.c
index d5f4086ca..9b66a1386 100644
--- a/imap4d/bye.c
+++ b/imap4d/bye.c
@@ -36,90 +36,102 @@ imap4d_bye0 (int reason, struct imap4d_command *command)
{
int status = EX_SOFTWARE;
- if (mbox)
+ /* Some clients may close the connection immediately after sending
+ LOGOUT. Do not treat this as error (RFC 2683).
+ To be on the safe side, ignore broken pipes for any command: at
+ this stage it is of no significance. */
+ static int sigtab[] = { SIGPIPE };
+ mu_set_signals (sigpipe, sigtab, MU_ARRAY_SIZE (sigtab));
+ if (setjmp (pipejmp))
{
- mu_mailbox_flush (mbox, 0);
- mu_mailbox_close (mbox);
- mu_mailbox_destroy (&mbox);
+ mu_set_signals (SIG_IGN, sigtab, MU_ARRAY_SIZE (sigtab));
+ /* Invalidate iostream. This creates a mild memory leak, as the
+ stream is not destroyed by util_bye, but at least this avoids
+ endless loop which would happen when mu_stream_flush would
+ try to flush buffers on an already broken pipe.
+ FIXME: There must be a special function for that, I guess.
+ Something like mu_stream_invalidate. */
+ iostream = NULL;
}
-
- switch (reason)
+ else
{
- case ERR_NO_MEM:
- io_untagged_response (RESP_BYE, "Server terminating: no more resources.");
- mu_diag_output (MU_DIAG_ERROR, _("not enough memory"));
- break;
-
- case ERR_TERMINATE:
- status = EX_OK;
- io_untagged_response (RESP_BYE, "Server terminating on request.");
- mu_diag_output (MU_DIAG_NOTICE, _("terminating on request"));
- break;
-
- case ERR_SIGNAL:
- mu_diag_output (MU_DIAG_ERROR, _("quitting on signal"));
- exit (status);
-
- case ERR_TIMEOUT:
- status = EX_TEMPFAIL;
- io_untagged_response (RESP_BYE, "Session timed out");
- if (state == STATE_NONAUTH)
- mu_diag_output (MU_DIAG_INFO, _("session timed out for no user"));
- else
- mu_diag_output (MU_DIAG_INFO, _("session timed out for user: %s"), auth_data->name);
- break;
-
- case ERR_NO_OFILE:
- status = EX_IOERR;
- mu_diag_output (MU_DIAG_INFO, _("write error on control stream"));
- break;
-
- case ERR_NO_IFILE:
- status = EX_IOERR;
- mu_diag_output (MU_DIAG_INFO, _("read error on control stream"));
- break;
-
- case ERR_MAILBOX_CORRUPTED:
- status = EX_OSERR;
- mu_diag_output (MU_DIAG_ERROR, _("mailbox modified by third party"));
- break;
-
- case ERR_STREAM_CREATE:
- status = EX_UNAVAILABLE;
- mu_diag_output (MU_DIAG_ERROR, _("cannot create transport stream"));
- break;
+ if (mbox)
+ {
+ imap4d_enter_critical ();
+ mu_mailbox_flush (mbox, 0);
+ mu_mailbox_close (mbox);
+ mu_mailbox_destroy (&mbox);
+ imap4d_leave_critical ();
+ }
+
+ switch (reason)
+ {
+ case ERR_NO_MEM:
+ io_untagged_response (RESP_BYE,
+ "Server terminating: no more resources.");
+ mu_diag_output (MU_DIAG_ERROR, _("not enough memory"));
+ break;
+
+ case ERR_TERMINATE:
+ status = EX_OK;
+ io_untagged_response (RESP_BYE, "Server terminating on request.");
+ mu_diag_output (MU_DIAG_NOTICE, _("terminating on request"));
+ break;
+
+ case ERR_SIGNAL:
+ mu_diag_output (MU_DIAG_ERROR, _("quitting on signal"));
+ exit (status);
+
+ case ERR_TIMEOUT:
+ status = EX_TEMPFAIL;
+ io_untagged_response (RESP_BYE, "Session timed out");
+ if (state == STATE_NONAUTH)
+ mu_diag_output (MU_DIAG_INFO, _("session timed out for no user"));
+ else
+ mu_diag_output (MU_DIAG_INFO, _("session timed out for user: %s"),
+ auth_data->name);
+ break;
+
+ case ERR_NO_OFILE:
+ status = EX_IOERR;
+ mu_diag_output (MU_DIAG_INFO, _("write error on control stream"));
+ break;
+
+ case ERR_NO_IFILE:
+ status = EX_IOERR;
+ mu_diag_output (MU_DIAG_INFO, _("read error on control stream"));
+ break;
+
+ case ERR_MAILBOX_CORRUPTED:
+ status = EX_OSERR;
+ mu_diag_output (MU_DIAG_ERROR, _("mailbox modified by third party"));
+ break;
+
+ case ERR_STREAM_CREATE:
+ status = EX_UNAVAILABLE;
+ mu_diag_output (MU_DIAG_ERROR, _("cannot create transport stream"));
+ break;
- case OK:
- status = EX_OK;
- io_untagged_response (RESP_BYE, "Session terminating.");
- if (state == STATE_NONAUTH)
- mu_diag_output (MU_DIAG_INFO, _("session terminating"));
- else
- mu_diag_output (MU_DIAG_INFO, _("session terminating for user: %s"), auth_data->name);
- break;
-
- default:
- io_untagged_response (RESP_BYE, "Quitting (reason unknown)");
- mu_diag_output (MU_DIAG_ERROR, _("quitting (numeric reason %d)"), reason);
- break;
- }
-
- if (status == EX_OK && command)
- {
- /* Some clients may close the connection immediately after sending
- LOGOUT. Do not treat this as error (RFC 2683). */
- static int sigtab[] = { SIGPIPE };
- mu_set_signals (sigpipe, sigtab, MU_ARRAY_SIZE (sigtab));
- if (setjmp (pipejmp) == 0)
+ case OK:
+ status = EX_OK;
+ io_untagged_response (RESP_BYE, "Session terminating.");
+ if (state == STATE_NONAUTH)
+ mu_diag_output (MU_DIAG_INFO, _("session terminating"));
+ else
+ mu_diag_output (MU_DIAG_INFO,
+ _("session terminating for user: %s"),
+ auth_data->name);
+ break;
+
+ default:
+ io_untagged_response (RESP_BYE, "Quitting (reason unknown)");
+ mu_diag_output (MU_DIAG_ERROR, _("quitting (numeric reason %d)"),
+ reason);
+ break;
+ }
+
+ if (status == EX_OK && command)
io_completion_response (command, RESP_OK, "Completed");
- else
- /* Invalidate iostream. This creates a mild memory leak, as the
- stream is not destroyed by util_bye, but at least this avoids
- endless loop which would happen when mu_stream_flush would
- try to flush buffers on an already broken pipe.
- FIXME: There must be a special function for that, I guess.
- Something like mu_stream_invalidate. */
- iostream = NULL;
}
util_bye ();
diff --git a/imap4d/close.c b/imap4d/close.c
index a5303f534..0b4c020ea 100644
--- a/imap4d/close.c
+++ b/imap4d/close.c
@@ -30,7 +30,9 @@ imap4d_close0 (struct imap4d_command *command, imap4d_tokbuf_t tok,
mu_mailbox_get_flags (mbox, &flags);
if (flags & MU_STREAM_WRITE)
{
+ imap4d_enter_critical ();
status = mu_mailbox_flush (mbox, expunge);
+ imap4d_leave_critical ();
if (status)
{
mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_flush", NULL, status);
@@ -40,7 +42,9 @@ imap4d_close0 (struct imap4d_command *command, imap4d_tokbuf_t tok,
/* No messages are removed, and no error is given, if the mailbox is
selected by an EXAMINE command or is otherwise selected read-only. */
+ imap4d_enter_critical ();
status = mu_mailbox_close (mbox);
+ imap4d_leave_critical ();
if (status)
{
mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_close", NULL, status);
diff --git a/imap4d/copy.c b/imap4d/copy.c
index dd0329644..69715df76 100644
--- a/imap4d/copy.c
+++ b/imap4d/copy.c
@@ -119,7 +119,9 @@ try_copy (mu_mailbox_t dst, mu_mailbox_t src, size_t n, size_t *set)
return RESP_BAD;
}
+ imap4d_enter_critical ();
status = mu_mailbox_append_message (dst, msg);
+ imap4d_leave_critical ();
if (status)
{
mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_append_message",
@@ -185,8 +187,10 @@ safe_copy (mu_mailbox_t dst, mu_mailbox_t src, size_t n, size_t *set,
mu_attribute_set_userflag (attr, MU_ATTRIBUTE_DELETED);
}
}
-
+
+ imap4d_enter_critical ();
status = mu_mailbox_flush (dst, 1);
+ imap4d_leave_critical ();
if (status)
{
mu_url_t url = NULL;
diff --git a/imap4d/delete.c b/imap4d/delete.c
index b3ab729ac..1e516e2a7 100644
--- a/imap4d/delete.c
+++ b/imap4d/delete.c
@@ -56,7 +56,9 @@ imap4d_delete (struct imap4d_command *command, imap4d_tokbuf_t tok)
rc = mu_mailbox_create (&tmpbox, name);
if (rc == 0)
{
+ imap4d_enter_critical ();
rc = mu_mailbox_remove (tmpbox);
+ imap4d_leave_critical ();
mu_mailbox_destroy (&tmpbox);
if (rc)
mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_remove", name, rc);
diff --git a/imap4d/expunge.c b/imap4d/expunge.c
index d9e5279ca..7a542bbe8 100644
--- a/imap4d/expunge.c
+++ b/imap4d/expunge.c
@@ -36,9 +36,11 @@ imap4d_expunge (struct imap4d_command *command, imap4d_tokbuf_t tok)
if (imap4d_tokbuf_argc (tok) != 2)
return io_completion_response (command, RESP_BAD, "Invalid arguments");
+ imap4d_enter_critical ();
/* FIXME: check for errors. */
mu_mailbox_expunge (mbox);
-
+ imap4d_leave_critical ();
+
imap4d_sync_invalidate ();
imap4d_sync ();
return io_completion_response (command, RESP_OK, "Completed");
diff --git a/imap4d/imap4d.c b/imap4d/imap4d.c
index a20167dc4..3c56ef194 100644
--- a/imap4d/imap4d.c
+++ b/imap4d/imap4d.c
@@ -385,11 +385,12 @@ get_client_address (int fd, struct sockaddr_in *pcs)
return 0;
}
+
void
imap4d_child_signal_setup (RETSIGTYPE (*handler) (int signo))
{
- static int sigtab[] = { SIGILL, SIGBUS, SIGFPE, SIGSEGV, SIGSTOP, SIGPIPE,
- SIGABRT, SIGINT, SIGQUIT, SIGTERM, SIGHUP, SIGALRM };
+ static int sigtab[] = { SIGPIPE, SIGABRT, SIGINT, SIGQUIT,
+ SIGTERM, SIGHUP, SIGALRM };
mu_set_signals (handler, sigtab, MU_ARRAY_SIZE (sigtab));
}
@@ -399,8 +400,40 @@ imap4d_mainloop (int ifd, int ofd)
imap4d_tokbuf_t tokp;
char *text;
int debug_mode = isatty (ifd);
+ int signo;
- imap4d_child_signal_setup (imap4d_child_signal);
+ if ((signo = setjmp (child_jmp)))
+ {
+ mu_diag_output (MU_DIAG_CRIT, _("got signal `%s'"), strsignal (signo));
+ switch (signo)
+ {
+ case SIGTERM:
+ case SIGHUP:
+ signo = ERR_TERMINATE;
+ break;
+
+ case SIGALRM:
+ signo = ERR_TIMEOUT;
+ break;
+
+ case SIGPIPE:
+ signo = ERR_NO_OFILE;
+ break;
+
+ default:
+ signo = ERR_SIGNAL;
+ }
+ imap4d_bye (signo);
+ }
+ else
+ {
+ /* Restore default handling for these signals: */
+ static int defsigtab[] = { SIGILL, SIGBUS, SIGFPE, SIGSEGV, SIGSTOP };
+ mu_set_signals (SIG_DFL, defsigtab, MU_ARRAY_SIZE (defsigtab));
+ /* Set child-specific signal handlers */
+ imap4d_child_signal_setup (imap4d_child_signal);
+ }
+
io_setio (ifd, ofd);
if (imap4d_preauth_setup (ifd) == 0)
@@ -484,6 +517,17 @@ imap4d_check_home_dir (const char *dir, uid_t uid, gid_t gid)
return 0;
}
+
+jmp_buf master_jmp;
+
+RETSIGTYPE
+imap4d_master_signal (int signo)
+{
+ longjmp (master_jmp, signo);
+}
+
+
+
int
main (int argc, char **argv)
{
@@ -578,6 +622,27 @@ main (int argc, char **argv)
}
/* Set the signal handlers. */
+ if ((status = setjmp (master_jmp)))
+ {
+ int code;
+ mu_diag_output (MU_DIAG_CRIT, _("MASTER: exiting on signal (%s)"),
+ strsignal (status));
+ switch (status)
+ {
+ case SIGTERM:
+ case SIGHUP:
+ case SIGQUIT:
+ case SIGINT:
+ code = EX_OK;
+ break;
+
+ default:
+ code = EX_SOFTWARE;
+ break;
+ }
+
+ exit (code);
+ }
mu_set_signals (imap4d_master_signal, sigtab, MU_ARRAY_SIZE (sigtab));
mu_stdstream_strerr_setup (mu_log_syslog ?
diff --git a/imap4d/imap4d.h b/imap4d/imap4d.h
index 61e082958..592d8122d 100644
--- a/imap4d/imap4d.h
+++ b/imap4d/imap4d.h
@@ -202,6 +202,7 @@ extern int imap4d_transcript;
extern mu_list_t imap4d_id_list;
extern int imap4d_argc;
extern char **imap4d_argv;
+extern jmp_buf child_jmp;
/* Input functions */
extern mu_stream_t iostream;
@@ -334,6 +335,9 @@ extern RETSIGTYPE imap4d_master_signal (int);
extern RETSIGTYPE imap4d_child_signal (int);
extern int imap4d_bye (int);
extern int imap4d_bye0 (int reason, struct imap4d_command *command);
+void imap4d_enter_critical (void);
+void imap4d_leave_critical (void);
+
/* Namespace functions */
extern mu_list_t namespace[NS_MAX];
diff --git a/imap4d/rename.c b/imap4d/rename.c
index f65b2978e..ccbfc2f51 100644
--- a/imap4d/rename.c
+++ b/imap4d/rename.c
@@ -182,12 +182,17 @@ imap4d_rename (struct imap4d_command *command, imap4d_tokbuf_t tok)
if (mu_mailbox_get_message (inbox, no, &message) == 0)
{
mu_attribute_t attr = NULL;
+
+ imap4d_enter_critical ();
mu_mailbox_append_message (newmbox, message);
+ imap4d_leave_critical ();
mu_message_get_attribute (message, &attr);
mu_attribute_set_deleted (attr);
}
}
+ imap4d_enter_critical ();
mu_mailbox_expunge (inbox);
+ imap4d_leave_critical ();
mu_mailbox_close (inbox);
mu_mailbox_destroy (&inbox);
}
diff --git a/imap4d/select.c b/imap4d/select.c
index 1ec75abec..c961e09bb 100644
--- a/imap4d/select.c
+++ b/imap4d/select.c
@@ -46,8 +46,10 @@ imap4d_select0 (struct imap4d_command *command, const char *mboxname,
currently selected mailbox without doing an expunge. */
if (mbox)
{
+ imap4d_enter_critical ();
mu_mailbox_sync (mbox);
mu_mailbox_close (mbox);
+ imap4d_leave_critical ();
mu_mailbox_destroy (&mbox);
/* Destroy the old uid table. */
imap4d_sync ();
diff --git a/imap4d/signal.c b/imap4d/signal.c
index 12d49a93f..74c3cdc61 100644
--- a/imap4d/signal.c
+++ b/imap4d/signal.c
@@ -15,57 +15,34 @@
You should have received a copy of the GNU General Public License
along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
-#define __USE_MISC
#include "imap4d.h"
-/* Default signal handler to call the imap4d_bye() function */
+jmp_buf child_jmp;
+static int __critical_section;
+static int __got_signal;
-RETSIGTYPE
-imap4d_master_signal (int signo)
+void
+imap4d_enter_critical ()
{
- int code;
-
- mu_diag_output (MU_DIAG_CRIT, _("MASTER: exiting on signal (%s)"),
- strsignal (signo));
- switch (signo)
- {
- case SIGTERM:
- case SIGHUP:
- case SIGQUIT:
- case SIGINT:
- code = EX_OK;
- break;
-
- default:
- code = EX_SOFTWARE;
- break;
- }
+ __critical_section = 1;
+ if (__got_signal)
+ __critical_section++;
+}
- exit (code);
+void
+imap4d_leave_critical ()
+{
+ if (__got_signal && __critical_section != 2)
+ longjmp (child_jmp, __got_signal);
+ __critical_section = 0;
}
RETSIGTYPE
imap4d_child_signal (int signo)
{
imap4d_child_signal_setup (SIG_IGN);
- mu_diag_output (MU_DIAG_CRIT, _("got signal `%s'"), strsignal (signo));
- switch (signo)
- {
- case SIGTERM:
- case SIGHUP:
- signo = ERR_TERMINATE;
- break;
-
- case SIGALRM:
- signo = ERR_TIMEOUT;
- break;
-
- case SIGPIPE:
- signo = ERR_NO_OFILE;
- break;
-
- default:
- signo = ERR_SIGNAL;
- }
- imap4d_bye (signo);
+ if (__critical_section)
+ __got_signal = signo;
+ else
+ longjmp (child_jmp, signo);
}
diff --git a/imap4d/status.c b/imap4d/status.c
index 9fa2ae889..33338981b 100644
--- a/imap4d/status.c
+++ b/imap4d/status.c
@@ -88,7 +88,9 @@ imap4d_status (struct imap4d_command *command, imap4d_tokbuf_t tok)
/* We may be opening the current mailbox, so make sure the attributes are
preserved */
+ imap4d_enter_critical ();
mu_mailbox_sync (mbox);
+ imap4d_leave_critical ();
status = mu_mailbox_create_default (&smbox, mailbox_name);
if (status == 0)
diff --git a/scheme/Makefile.am b/scheme/Makefile.am
index c146dfb96..cede42b6b 100644
--- a/scheme/Makefile.am
+++ b/scheme/Makefile.am
@@ -56,5 +56,6 @@ sievemod_DATA=\
EXTRA_DIST=\
$(sievemod_DATA)\
sieve-core.scm\
- sieve2scm.scmi
+ sieve2scm.scmi\
+ guimb.scmi

Return to:

Send suggestions and report system problems to the System administrator.