summaryrefslogtreecommitdiff
path: root/libmailutils
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2020-11-30 18:49:48 +0200
committerSergey Poznyakoff <gray@gnu.org>2020-11-30 18:49:48 +0200
commit23404fbf27b67bd1767998918548aee3235f201c (patch)
treed3557c6336910a53f9f8dc83568195e383d10b4d /libmailutils
parent42e0f735b48ab0f05e80eeec335684b25a93c4a3 (diff)
downloadmailutils-23404fbf27b67bd1767998918548aee3235f201c.tar.gz
mailutils-23404fbf27b67bd1767998918548aee3235f201c.tar.bz2
New functions for closing all fds and daemonizing
* configure.ac: Select a suitable interface for closing all file descriptors greater than or equal to a chosen one. * include/mailutils/daemon.h (mu_daemon): New proto. * include/mailutils/util.h (mu_close_fds): New proto. * lib/daemon.c: Removed. * lib/Makefile.am: Remove daemon.c * libmailutils/base/Makefile.am: Add closefds.c * libmailutils/base/closefds.c: New file. * libmailutils/base/daemon.c: Rename to libmailutils/base/pidfile.c * libmailutils/base/daemon.c: New file. * libmailutils/diag/bt.c: Use mu_close_fds. * libmailutils/server/acl.c: Likewise. * mh/mh_whatnow.c: Likewise. * libmailutils/stream/prog_stream.c: Likewise. * libmailutils/server/msrv.c: Use mu_daemon. * mh/send.c: Likewise. * mda/lib/util.c (mda_close_fds): Remove.
Diffstat (limited to 'libmailutils')
-rw-r--r--libmailutils/base/Makefile.am2
-rw-r--r--libmailutils/base/closefds.c129
-rw-r--r--libmailutils/base/daemon.c220
-rw-r--r--libmailutils/base/pidfile.c187
-rw-r--r--libmailutils/diag/bt.c4
-rw-r--r--libmailutils/server/acl.c7
-rw-r--r--libmailutils/server/msrv.c4
-rw-r--r--libmailutils/stream/prog_stream.c3
8 files changed, 385 insertions, 171 deletions
diff --git a/libmailutils/base/Makefile.am b/libmailutils/base/Makefile.am
index 3d6820c77..d56938751 100644
--- a/libmailutils/base/Makefile.am
+++ b/libmailutils/base/Makefile.am
@@ -24,6 +24,7 @@ libbase_la_SOURCES = \
argcvjoin.c\
argcvrem.c\
assoc.c\
+ closefds.c\
coord.c\
copyfile.c\
ctparse.c\
@@ -55,6 +56,7 @@ libbase_la_SOURCES = \
onexit.c\
opool.c\
permstr.c\
+ pidfile.c\
registrar.c\
refcount.c\
renamefile.c\
diff --git a/libmailutils/base/closefds.c b/libmailutils/base/closefds.c
new file mode 100644
index 000000000..49c024fb1
--- /dev/null
+++ b/libmailutils/base/closefds.c
@@ -0,0 +1,129 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+ Copyright (C) 2019-2020 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, 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 GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
+#include <config.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <mailutils/util.h>
+
+#if defined (HAVE_FUNC_CLOSEFROM)
+# include <unistd.h>
+
+static int
+close_fds_sys (int minfd)
+{
+ closefrom (minfd);
+ return 0;
+}
+
+#elif defined (HAVE_FCNTL_CLOSEM)
+# include <fcntl.h>
+
+static int
+close_fds_sys (int minfd)
+{
+ fcntl (minfd, F_CLOSEM, 0);
+ return 0;
+}
+
+#elif defined (HAVE_LIBPROC_H) && defined (HAVE_FUNC_PROC_PIDINFO)
+#include <libproc.h>
+
+static int
+close_fds_sys (int minfd)
+{
+ pid_t pid = getpid ();
+ struct proc_fdinfo *fdinfo;
+ int i, n, size;
+
+ size = proc_pidinfo (pid, PROC_PIDLISTFDS, 0, NULL, 0);
+ if (size == 0)
+ return 0;
+ else if (size < 0)
+ return -1;
+
+ fdinfo = calloc (size, sizeof (fdinfo[0]));
+ if (!fdinfo)
+ return -1;
+
+ n = proc_pidinfo (pid, PROC_PIDLISTFDS, 0, fdinfo, size);
+ if (n <= 0)
+ {
+ free (fdinfo);
+ return -1;
+ }
+
+ n /= PROC_PIDLISTFD_SIZE;
+
+ for (i = minfd; i < n; i++)
+ {
+ close (fdinfo_buf[i].proc_fd);
+ }
+
+ free (fdinfo);
+ return 0;
+}
+
+#elif defined (HAVE_PROC_SELF_FD)
+# include <sys/types.h>
+# include <dirent.h>
+# include <limits.h>
+
+static int
+close_fds_sys (int minfd)
+{
+ DIR *dir;
+ struct dirent *ent;
+
+ dir = opendir ("/proc/self/fd");
+ if (!dir)
+ return -1;
+ while ((ent = readdir (dir)) != NULL)
+ {
+ long n;
+ char *p;
+
+ if (ent->d_name[0] == '.')
+ continue;
+
+ n = strtol (ent->d_name, &p, 10);
+ if (n >= minfd && n < INT_MAX && *p == 0)
+ close ((int) n);
+ }
+ closedir (dir);
+ return 0;
+}
+
+#else
+# define close_fds_sys(fd) (-1)
+#endif
+
+static int
+close_fds_bruteforce (int minfd)
+{
+ int i, n = mu_getmaxfd ();
+
+ for (i = minfd; i < n; i++)
+ close (i);
+
+ return 0;
+}
+
+void
+mu_close_fds (int minfd)
+{
+ if (close_fds_sys (minfd))
+ close_fds_bruteforce (minfd);
+}
diff --git a/libmailutils/base/daemon.c b/libmailutils/base/daemon.c
index a2a3252ca..d7ca0c6cd 100644
--- a/libmailutils/base/daemon.c
+++ b/libmailutils/base/daemon.c
@@ -1,187 +1,87 @@
/* GNU Mailutils -- a suite of utilities for electronic mail
- Copyright (C) 2004-2020 Free Software Foundation, Inc.
+ Copyright (C) 2019-2020 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 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, 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.
+ 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 <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
+ You should have received a copy of the GNU Lesser General Public License
+ along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
+#include <config.h>
+#include <confpaths.h>
#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <string.h>
-
+#include <unistd.h>
+#include <unistd.h>
+#include <errno.h>
+#include <signal.h>
+#include <mailutils/util.h>
#include <mailutils/daemon.h>
-#include <mailutils/errno.h>
-#include <mailutils/error.h>
-#include <mailutils/nls.h>
-
-static char *pidfile;
-static pid_t current_pid;
-
-/* Return 0 if DIR is writable for EUID/EGID.
- Otherwise, return error code. */
-static int
-ewraccess (const char *dir)
-{
- struct stat st;
- if (stat (dir, &st))
- return errno;
- if ((st.st_mode & S_IWOTH)
- || (st.st_gid == getegid () && (st.st_mode & S_IWGRP))
- || (st.st_uid == geteuid () && (st.st_mode & S_IWUSR)))
- return 0;
- else
- return EACCES;
-}
-
-/* Return 0 if DIR is writable. If necessary and possible, raise to
- EUID 0, in that case return prior EUID in the memory location pointed to
- by PUID. */
-static int
-access_dir (const char *dir, uid_t *puid)
-{
- int ec = ewraccess (dir);
- if (ec)
- {
- if (ec == EACCES && access (dir, W_OK) == 0)
- {
- uid_t uid = geteuid ();
- /* See if we can become root */
- if (uid && getuid () == 0 && seteuid (0) == 0)
- {
- *puid = uid;
- return 0;
- }
- }
- }
- return ec;
-}
int
-mu_daemon_create_pidfile (const char *filename)
+mu_daemon (void)
{
- char *p;
int fd;
- uid_t uid = 0;
- int rc;
- if (filename[0] != '/')
- return EINVAL;
+ switch (fork ())
+ {
+ case 0:
+ break;
- if (pidfile)
- free (pidfile);
- pidfile = strdup (filename);
- if (!pidfile)
- return ENOMEM;
+ case -1:
+ return errno;
- /* Determine the hosting directory name */
- p = strrchr (pidfile, '/');
- if (pidfile == p)
- {
- free (pidfile);
- pidfile = NULL;
- /* Sorry, pidfiles in root dir are not allowed */
- return EINVAL;
- }
- /* Check if we have write access to the directory */
- *p = 0;
- rc = access_dir (pidfile, &uid);
- if (rc)
- {
- /* Nope, clean up and return */
- free (pidfile);
- pidfile = NULL;
- return rc;
+ default:
+ _exit (0);
}
- /* Restore directory separator */
- *p = '/';
-
- unlink (pidfile);
- current_pid = getpid ();
+ if (setsid () == (pid_t) -1)
+ return errno;
+
+ signal (SIGHUP, SIG_IGN);
- if ((fd = open (pidfile, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 0644)) != -1)
+ switch (fork ())
{
- FILE *fp = fdopen (fd, "w");
- if (!fp)
- {
- rc = errno;
- free (pidfile);
- close (fd);
- }
- else
- {
- fprintf (fp, "%lu", (unsigned long) current_pid);
- fclose (fp);
- atexit (mu_daemon_remove_pidfile);
- }
- }
- else
- {
- rc = errno;
- free (pidfile);
- pidfile = NULL;
- }
+ case 0:
+ break;
- /* Restore previous EUID value. */
- if (uid)
- seteuid (uid);
-
- return rc;
-}
+ case -1:
+ return errno;
-void
-mu_daemon_remove_pidfile (void)
-{
- if (getpid () == current_pid)
- {
- int rc;
- uid_t uid = 0;
+ default:
+ _exit (0);
+ }
- /* Determine the hosting directory name */
- char *p = strrchr (pidfile, '/');
- if (pidfile == p)
- {
- /* Should not happen */
- abort ();
- }
- /* Check if we have write access to the directory */
- *p = 0;
- rc = access_dir (pidfile, &uid);
- *p = '/';
- if (rc == 0)
- {
- if (unlink (pidfile) && errno != ENOENT)
- rc = errno;
- else
- rc = 0;
- }
-
- if (rc)
- mu_error (_("cannot remove pidfile %s: %s"),
- pidfile, mu_strerror (rc));
+ chdir ("/");
+ mu_close_fds (0);
- free (pidfile);
- pidfile = NULL;
+ fd = open (PATH_DEVNULL, O_RDWR);
+ if (fd == 0)
+ {
+ dup2 (fd, 1);
+ dup2 (fd, 2);
+ }
+ else if (fd > 0)
+ {
+ /* This means that mu_close_fds failed to close stdin.
+ Shouldn't happen, but just in case ... */
+ dup2 (fd, 0);
+ dup2 (fd, 1);
+ dup2 (fd, 2);
+ close (fd);
}
+
+ return 0;
}
-
+
+
+
+
+
diff --git a/libmailutils/base/pidfile.c b/libmailutils/base/pidfile.c
new file mode 100644
index 000000000..a2a3252ca
--- /dev/null
+++ b/libmailutils/base/pidfile.c
@@ -0,0 +1,187 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+ Copyright (C) 2004-2020 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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+
+#include <mailutils/daemon.h>
+#include <mailutils/errno.h>
+#include <mailutils/error.h>
+#include <mailutils/nls.h>
+
+static char *pidfile;
+static pid_t current_pid;
+
+/* Return 0 if DIR is writable for EUID/EGID.
+ Otherwise, return error code. */
+static int
+ewraccess (const char *dir)
+{
+ struct stat st;
+ if (stat (dir, &st))
+ return errno;
+ if ((st.st_mode & S_IWOTH)
+ || (st.st_gid == getegid () && (st.st_mode & S_IWGRP))
+ || (st.st_uid == geteuid () && (st.st_mode & S_IWUSR)))
+ return 0;
+ else
+ return EACCES;
+}
+
+/* Return 0 if DIR is writable. If necessary and possible, raise to
+ EUID 0, in that case return prior EUID in the memory location pointed to
+ by PUID. */
+static int
+access_dir (const char *dir, uid_t *puid)
+{
+ int ec = ewraccess (dir);
+ if (ec)
+ {
+ if (ec == EACCES && access (dir, W_OK) == 0)
+ {
+ uid_t uid = geteuid ();
+ /* See if we can become root */
+ if (uid && getuid () == 0 && seteuid (0) == 0)
+ {
+ *puid = uid;
+ return 0;
+ }
+ }
+ }
+ return ec;
+}
+
+int
+mu_daemon_create_pidfile (const char *filename)
+{
+ char *p;
+ int fd;
+ uid_t uid = 0;
+ int rc;
+
+ if (filename[0] != '/')
+ return EINVAL;
+
+ if (pidfile)
+ free (pidfile);
+ pidfile = strdup (filename);
+ if (!pidfile)
+ return ENOMEM;
+
+ /* Determine the hosting directory name */
+ p = strrchr (pidfile, '/');
+ if (pidfile == p)
+ {
+ free (pidfile);
+ pidfile = NULL;
+ /* Sorry, pidfiles in root dir are not allowed */
+ return EINVAL;
+ }
+ /* Check if we have write access to the directory */
+ *p = 0;
+ rc = access_dir (pidfile, &uid);
+ if (rc)
+ {
+ /* Nope, clean up and return */
+ free (pidfile);
+ pidfile = NULL;
+ return rc;
+ }
+
+ /* Restore directory separator */
+ *p = '/';
+
+ unlink (pidfile);
+ current_pid = getpid ();
+
+ if ((fd = open (pidfile, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 0644)) != -1)
+ {
+ FILE *fp = fdopen (fd, "w");
+ if (!fp)
+ {
+ rc = errno;
+ free (pidfile);
+ close (fd);
+ }
+ else
+ {
+ fprintf (fp, "%lu", (unsigned long) current_pid);
+ fclose (fp);
+ atexit (mu_daemon_remove_pidfile);
+ }
+ }
+ else
+ {
+ rc = errno;
+ free (pidfile);
+ pidfile = NULL;
+ }
+
+ /* Restore previous EUID value. */
+ if (uid)
+ seteuid (uid);
+
+ return rc;
+}
+
+void
+mu_daemon_remove_pidfile (void)
+{
+ if (getpid () == current_pid)
+ {
+ int rc;
+ uid_t uid = 0;
+
+ /* Determine the hosting directory name */
+ char *p = strrchr (pidfile, '/');
+ if (pidfile == p)
+ {
+ /* Should not happen */
+ abort ();
+ }
+ /* Check if we have write access to the directory */
+ *p = 0;
+ rc = access_dir (pidfile, &uid);
+ *p = '/';
+ if (rc == 0)
+ {
+ if (unlink (pidfile) && errno != ENOENT)
+ rc = errno;
+ else
+ rc = 0;
+ }
+
+ if (rc)
+ mu_error (_("cannot remove pidfile %s: %s"),
+ pidfile, mu_strerror (rc));
+
+ free (pidfile);
+ pidfile = NULL;
+ }
+}
+
+
+
diff --git a/libmailutils/diag/bt.c b/libmailutils/diag/bt.c
index c27634ef2..3b43dcd21 100644
--- a/libmailutils/diag/bt.c
+++ b/libmailutils/diag/bt.c
@@ -36,7 +36,6 @@
void
mu_gdb_bt ()
{
- int i;
pid_t master_pid = getpid ();
pid_t pid;
static char buf[1024];
@@ -58,8 +57,7 @@ mu_gdb_bt ()
abort ();
}
- for (i = mu_getmaxfd (); i >= 0; i--)
- close (i);
+ mu_close_fds (0);
fd = open (fname, O_WRONLY|O_CREAT, 0600);
if (fd == -1)
diff --git a/libmailutils/server/acl.c b/libmailutils/server/acl.c
index f209d6929..5f71d2bce 100644
--- a/libmailutils/server/acl.c
+++ b/libmailutils/server/acl.c
@@ -410,7 +410,6 @@ spawn_prog (const char *cmdline, int *pstatus, struct run_closure *rp)
pid = fork ();
if (pid == 0)
{
- int i;
struct mu_wordsplit ws;
if (mu_wordsplit (s, &ws, MU_WRDSF_DEFFLAGS))
@@ -419,9 +418,9 @@ spawn_prog (const char *cmdline, int *pstatus, struct run_closure *rp)
mu_wordsplit_strerror (&ws));
_exit (127);
}
-
- for (i = mu_getmaxfd (); i > 2; i--)
- close (i);
+
+ mu_close_fds (3);
+
execvp (ws.ws_wordv[0], ws.ws_wordv);
_exit (127);
}
diff --git a/libmailutils/server/msrv.c b/libmailutils/server/msrv.c
index 088f4d8b3..6203ae71c 100644
--- a/libmailutils/server/msrv.c
+++ b/libmailutils/server/msrv.c
@@ -522,9 +522,9 @@ mu_m_server_begin (mu_m_server_t msrv)
{
/* Become a daemon. Take care to close inherited fds and to hold
first three one, in, out, err */
- if (daemon (0, 0) < 0)
+ if ((rc = mu_daemon ()) != 0)
{
- mu_error (_("failed to become a daemon: %s"), mu_strerror (errno));
+ mu_error (_("failed to become a daemon: %s"), mu_strerror (rc));
exit (EXIT_FAILURE);
}
mu_onexit_reset ();
diff --git a/libmailutils/stream/prog_stream.c b/libmailutils/stream/prog_stream.c
index 08a19af2a..61ccfd39a 100644
--- a/libmailutils/stream/prog_stream.c
+++ b/libmailutils/stream/prog_stream.c
@@ -252,8 +252,7 @@ start_program_filter (int *p, struct _mu_prog_stream *fs, int flags)
}
/* Close unneded descripitors */
- for (i = mu_getmaxfd (); i > 2; i--)
- close (i);
+ mu_close_fds (3);
/*FIXME: Switch to other uid/gid if desired */
execvp (fs->progname, fs->argv);

Return to:

Send suggestions and report system problems to the System administrator.