aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2009-09-15 10:40:29 +0300
committerSergey Poznyakoff <gray@gnu.org.ua>2009-09-15 10:40:54 +0300
commit989a5bbb74c3620abaa2191ce2c4f8d5968dbf0a (patch)
treec0b2324a523905c3c17201cc2468c9078976fc74 /lib
parentdbad35177723e19147ab49b59a3728e00fe05875 (diff)
downloadpies-989a5bbb74c3620abaa2191ce2c4f8d5968dbf0a.tar.gz
pies-989a5bbb74c3620abaa2191ce2c4f8d5968dbf0a.tar.bz2
Branch off from the Mailfromd project into a separate repository.
Diffstat (limited to 'lib')
-rw-r--r--lib/Makefile.am33
-rw-r--r--lib/config.c115
-rw-r--r--lib/intprops.h79
-rw-r--r--lib/libpies.h70
-rw-r--r--lib/nls.c34
-rw-r--r--lib/parsetime.c109
-rw-r--r--lib/proctitle.c164
-rw-r--r--lib/userprivs.c291
8 files changed, 895 insertions, 0 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am
new file mode 100644
index 0000000..f83e7e3
--- /dev/null
+++ b/lib/Makefile.am
@@ -0,0 +1,33 @@
+# This file is part of Mailfromd.
+# Copyright (C) 2005, 2006, 2007, 2008 Sergey Poznyakoff
+#
+# 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 Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+noinst_LIBRARIES=libmf.a
+
+noinst_HEADERS = libpies.h
+
+libmf_a_SOURCES=\
+ config.c\
+ nls.c\
+ parsetime.c\
+ proctitle.c\
+ userprivs.c
+
+libmf_a_LIBADD=$(LIBOBJS)
+
+INCLUDES = -I$(top_srcdir)/gnu -I../gnu
+
+AM_CPPFLAGS=-DLOCALEDIR=\"$(localedir)\"
+
diff --git a/lib/config.c b/lib/config.c
new file mode 100644
index 0000000..8fcb926
--- /dev/null
+++ b/lib/config.c
@@ -0,0 +1,115 @@
+/* This file is part of Pies.
+ Copyright (C) 2007, 2008, 2009 Sergey Poznyakoff
+
+ 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 Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <libpies.h>
+
+
+char **
+config_array_to_argv (mu_config_value_t *val, mu_debug_t debug)
+{
+ int i, j;
+ int argc;
+ char **argv;
+
+ argc = val->v.arg.c;
+ argv = xcalloc (argc + 1, sizeof (argv[0]));
+ for (i = j = 0; i < argc; i++)
+ {
+ if (mu_cfg_assert_value_type (&val->v.arg.v[i], MU_CFG_STRING,
+ debug) == 0)
+ argv[j++] = xstrdup (val->v.arg.v[i].v.string);
+ }
+ argv[j] = NULL;
+ return argv;
+}
+
+char *
+config_array_to_string (mu_config_value_t *val, mu_debug_t debug)
+{
+ size_t len = 0;
+ int i;
+ char *str, *p;
+
+ for (i = 0; i < val->v.arg.c; i++)
+ {
+ if (mu_cfg_assert_value_type (&val->v.arg.v[i], MU_CFG_STRING, debug))
+ return NULL;
+ len += strlen (val->v.arg.v[i].v.string) + 1;
+ }
+
+ str = xmalloc (len);
+ p = str;
+ for (i = 0; i < val->v.arg.c; i++)
+ {
+ size_t n = strlen (val->v.arg.v[i].v.string);
+ memcpy (p, val->v.arg.v[i].v.string, n);
+ p += n;
+ *p++ = ' ';
+ }
+ str[len-1] = 0;
+ return str;
+}
+
+
+int
+config_cb_timeout (struct timeval *pt, mu_debug_t debug,
+ mu_config_value_t *val)
+{
+ int rc;
+ const char *endp;
+ time_t t;
+ const char *str;
+ char *alloc_str = NULL;
+
+ switch (val->type)
+ {
+ case MU_CFG_STRING:
+ str = val->v.string;
+ break;
+
+ case MU_CFG_ARRAY:
+ str = alloc_str = config_array_to_string (val, debug);
+ if (!str)
+ return 1;
+ break;
+
+ case MU_CFG_LIST:
+ mu_cfg_format_error (debug, MU_DEBUG_ERROR,
+ _("unexpected list"));
+ return 1;
+ }
+
+ rc = parse_time_interval (str, &t, &endp);
+ if (rc)
+ mu_cfg_format_error (debug, MU_DEBUG_ERROR,
+ _("unrecognized time format (near `%s')"),
+ endp);
+ else
+ {
+ pt->tv_usec = 0;
+ pt->tv_sec = t;
+ }
+ free (alloc_str);
+ return 0;
+}
+
+
+
+
diff --git a/lib/intprops.h b/lib/intprops.h
new file mode 100644
index 0000000..7db55e9
--- /dev/null
+++ b/lib/intprops.h
@@ -0,0 +1,79 @@
+/* intprops.h -- properties of integer types
+
+ Copyright (C) 2001, 2002, 2003, 2004, 2005,
+ 2007 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 Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* Written by Paul Eggert. */
+
+#include <limits.h>
+
+/* The extra casts in the following macros work around compiler bugs,
+ e.g., in Cray C 5.0.3.0. */
+
+/* True if the arithmetic type T is an integer type. bool counts as
+ an integer. */
+#define TYPE_IS_INTEGER(t) ((t) 1.5 == 1)
+
+/* True if negative values of the signed integer type T use two's
+ complement, ones' complement, or signed magnitude representation,
+ respectively. Much GNU code assumes two's complement, but some
+ people like to be portable to all possible C hosts. */
+#define TYPE_TWOS_COMPLEMENT(t) ((t) ~ (t) 0 == (t) -1)
+#define TYPE_ONES_COMPLEMENT(t) ((t) ~ (t) 0 == 0)
+#define TYPE_SIGNED_MAGNITUDE(t) ((t) ~ (t) 0 < (t) -1)
+
+/* True if the arithmetic type T is signed. */
+#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
+
+/* The maximum and minimum values for the integer type T. These
+ macros have undefined behavior if T is signed and has padding bits.
+ If this is a problem for you, please let us know how to fix it for
+ your host. */
+#define TYPE_MINIMUM(t) \
+ ((t) (! TYPE_SIGNED (t) \
+ ? (t) 0 \
+ : TYPE_SIGNED_MAGNITUDE (t) \
+ ? ~ (t) 0 \
+ : ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1)))
+#define TYPE_MAXIMUM(t) \
+ ((t) (! TYPE_SIGNED (t) \
+ ? (t) -1 \
+ : ~ (~ (t) 0 << (sizeof (t) * CHAR_BIT - 1))))
+
+/* Return zero if T can be determined to be an unsigned type.
+ Otherwise, return 1.
+ When compiling with GCC, INT_STRLEN_BOUND uses this macro to obtain a
+ tighter bound. Otherwise, it overestimates the true bound by one byte
+ when applied to unsigned types of size 2, 4, 16, ... bytes.
+ The symbol signed_type_or_expr__ is private to this header file. */
+#if __GNUC__ >= 2
+# define signed_type_or_expr__(t) TYPE_SIGNED (__typeof__ (t))
+#else
+# define signed_type_or_expr__(t) 1
+#endif
+
+/* Bound on length of the string representing an integer type or expression T.
+ Subtract 1 for the sign bit if T is signed; log10 (2.0) < 146/485;
+ add 1 for integer division truncation; add 1 more for a minus sign
+ if needed. */
+#define INT_STRLEN_BOUND(t) \
+ ((sizeof (t) * CHAR_BIT - signed_type_or_expr__ (t)) * 146 / 485 \
+ + signed_type_or_expr__ (t) + 1)
+
+/* Bound on buffer size needed to represent an integer type or expression T,
+ including the terminating null. */
+#define INT_BUFSIZE_BOUND(t) (INT_STRLEN_BOUND (t) + 1)
diff --git a/lib/libpies.h b/lib/libpies.h
new file mode 100644
index 0000000..4733c63
--- /dev/null
+++ b/lib/libpies.h
@@ -0,0 +1,70 @@
+/* This file is part of Pies.
+ Copyright (C) 2009 Sergey Poznyakoff
+
+ 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 Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <gettext.h>
+#include <mailutils/types.h>
+#include <mailutils/cfg.h>
+
+
+#define _(String) gettext(String)
+#define N_(String) String
+
+
+#if defined HAVE_SYSCONF && defined _SC_OPEN_MAX
+# define getmaxfd() sysconf(_SC_OPEN_MAX)
+#elif defined (HAVE_GETDTABLESIZE)
+# define getmaxfd() getdtablesize()
+#else
+# define getmaxfd() 256
+#endif
+
+
+
+void *xmalloc (size_t size);
+void *xzalloc (size_t size);
+void *xcalloc (size_t count, size_t size);
+char *xstrdup (const char *str);
+
+
+struct mf_privs
+{
+ char *user;
+ int allgroups;
+ mu_list_t groups;
+};
+
+int switch_to_privs (uid_t uid, gid_t gid, mu_list_t retain_groups);
+int get_user_groups (mu_list_t *pgrouplist, const char *user);
+
+void mf_priv_setup (struct mf_privs *);
+void mf_epriv_setup (struct mf_privs *);
+
+
+char **config_array_to_argv (mu_config_value_t *val, mu_debug_t debug);
+char *config_array_to_string (mu_config_value_t *val, mu_debug_t debug);
+
+int config_cb_timeout (struct timeval *pt, mu_debug_t debug,
+ mu_config_value_t *val);
+
+
+void mf_proctitle_init (int argc, char *argv[], char *env[]);
+void mf_proctitle_format (const char *fmt, ...);
+
+
+size_t longtostr (long i, char *buf, size_t size);
+size_t ulongtostr (unsigned long i, char *buf, size_t size);
diff --git a/lib/nls.c b/lib/nls.c
new file mode 100644
index 0000000..f2b067e
--- /dev/null
+++ b/lib/nls.c
@@ -0,0 +1,34 @@
+/* This file is part of Mailfromd.
+ Copyright (C) 2007, 2008 Sergey Poznyakoff
+
+ 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 Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <libpies.h>
+#include <locale.h>
+#include <mailutils/nls.h>
+
+void
+mf_init_nls ()
+{
+#ifdef ENABLE_NLS
+ mu_init_nls ();
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ bindtextdomain ("mailfromd", LOCALEDIR);
+ textdomain (PACKAGE);
+#endif
+}
diff --git a/lib/parsetime.c b/lib/parsetime.c
new file mode 100644
index 0000000..99d8079
--- /dev/null
+++ b/lib/parsetime.c
@@ -0,0 +1,109 @@
+/* This file is part of Pies.
+ Copyright (C) 2007, 2008, 2009 Sergey Poznyakoff
+
+ 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 Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <c-ctype.h>
+
+static int
+time_multiplier(const char *str, unsigned *m, unsigned *plen)
+{
+ static struct timetab {
+ char *name;
+ unsigned mul;
+ } tab[] = {
+ { "seconds", 1 },
+ { "minutes", 60 },
+ { "hours", 60*60 },
+ { "days", 24*60*60 },
+ { "weeks", 7*24*60*60 },
+ { "months", 31*7*24*60*60 },
+ { NULL }
+ };
+ struct timetab *p;
+ int slen;
+
+ for (slen = 0; str[slen]; slen++)
+ if (c_isspace(str[slen]))
+ break;
+
+ for (p = tab; p->name; p++) {
+ if (p->name[0] == c_tolower(str[0])) {
+ int nlen = strlen(p->name);
+
+ if (nlen > slen)
+ nlen = slen;
+
+ if (strncasecmp(p->name, str, nlen) == 0) {
+ *m = p->mul;
+ if (plen)
+ *plen = nlen;
+ return 0;
+ }
+ }
+ }
+ return 1;
+}
+
+int
+parse_time_interval(const char *str, time_t *pint, const char **endp)
+{
+ int rc = 0;
+ time_t interval = 0;
+
+ while (*str) {
+ char *p;
+ unsigned long n;
+ unsigned mul, len;
+
+ while (*str && c_isspace(*str))
+ str++;
+
+ if (!c_isdigit(*str) && time_multiplier(str, &mul, &len) == 0) {
+ n = 1;
+ str += len;
+ } else {
+ n = strtoul(str, &p, 10);
+ if (*p && !c_isspace(*p)) {
+ str = p;
+ rc = 1;
+ break;
+ }
+
+ while (*p && c_isspace(*p))
+ p++;
+
+ str = p;
+ if (*str) {
+ if (rc = time_multiplier(str, &mul, &len))
+ break;
+ str += len;
+ } else
+ mul = 1;
+ }
+ interval += n*mul;
+ }
+
+ if (rc && endp)
+ *endp = str;
+ *pint = interval;
+ return rc;
+}
+
diff --git a/lib/proctitle.c b/lib/proctitle.c
new file mode 100644
index 0000000..f9ff967
--- /dev/null
+++ b/lib/proctitle.c
@@ -0,0 +1,164 @@
+/* This file is part of Mailfromd.
+ Copyright (C) 2007, 2008 Sergey Poznyakoff
+
+ 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 Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#if MF_PROCTITLE_TYPE == MF_PROCTITLE_PSTAT
+# include <sys/pstat.h>
+#elif MF_PROCTITLE_TYPE == MF_PROCTITLE_PSSTRINGS
+# include <sys/proc.h>
+# include <vm/pmap.h>
+# include <machine/pmap.h>
+# include <machine/vmparam.h>
+# include <sys/exec.h>
+#endif
+
+extern char **environ;
+
+/* Move the environment to prepare more space for argv */
+static int
+move_env (char *env[])
+{
+ size_t size;
+ int i;
+ char **p;
+
+ size = 0;
+ for (i = 0; env[i]; i++)
+ size += strlen (env[i]) + 1;
+
+ p = calloc (i + 1, sizeof (*p));
+ if (!p)
+ return 1;
+
+ for (i = 0; env[i]; i++)
+ if ((p[i] = strdup(env[i])) == NULL) {
+ int j;
+ /* Free allocated memory and return */
+ for (j = 0; j < i; j++)
+ free(p[i]);
+ free(p);
+ return 1;
+ }
+ p[i] = NULL;
+ environ = p;
+ return 0;
+}
+
+static int orig_argc;
+static char **orig_argv;
+static char *orig_argv_end;
+static char *proctitle_buffer;
+#ifdef HAVE___PROGNAME
+extern char *__progname;
+extern char *__progname_full;
+#else
+static char *__progname;
+#endif
+
+void
+mf_proctitle_init (int argc, char *argv[], char *env[])
+{
+ int i;
+
+ move_env (env);
+
+ orig_argc = argc;
+ orig_argv = argv;
+ orig_argv_end = argv[0] + strlen (argv[0]);
+ __progname = strrchr (argv[0], '/');
+ if (__progname)
+ __progname++;
+ else
+ __progname = argv[0];
+ __progname = strdup (__progname);
+#ifdef HAVE___PROGNAME
+ __progname_full = strdup(argv[0]);
+#endif
+
+ for (i = 0; i < orig_argc; i++) {
+ if (orig_argv_end + 1 == argv[i])
+ orig_argv_end = argv[i] + strlen(argv[i]);
+ }
+
+ for (i = 0; env[i]; i++) {
+ if ((orig_argv_end + 1) == env[i])
+ orig_argv_end = env[i] + strlen(env[i]);
+ }
+}
+
+static void
+mf_proctitle_flush ()
+{
+#if MF_PROCTITLE_TYPE == MF_PROCTITLE_SETPROCTITLE
+ setproctitle ("%s", proctitle_buffer);
+#elif MF_PROCTITLE_TYPE == MF_PROCTITLE_REPLACE_ARGV
+ orig_argv[0] = proctitle_buffer;
+ for (i = 1; i < orig_argc; i++) {
+ orig_argv[i] = "";
+ }
+#elif MF_PROCTITLE_TYPE == MF_PROCTITLE_REWRITE_ARGV
+ size_t argv_size = orig_argv_end - orig_argv[0] - 2;
+ size_t len = strlen (proctitle_buffer);
+ memset (orig_argv[0], 0, argv_size);
+ if (len > argv_size)
+ len = argv_size;
+ memcpy (orig_argv[0], proctitle_buffer, len);
+ orig_argv[0][len] = 0;
+#elif MF_PROCTITLE_TYPE == MF_PROCTITLE_PSTAT
+ union pstun pst;
+ pst.pst_command = proc_title_buf;
+ pstat(PSTAT_SETCMD, pst, strlen (proctitle_buffer), 0, 0);
+#elif MF_PROCTITLE_TYPE == MF_PROCTITLE_PSSTRINGS
+ PS_STRINGS->ps_nargvstr = 1;
+ PS_STRINGS->ps_argvstr = proctitle_buffer;
+#endif
+}
+
+void
+mf_proctitle_format (const char *fmt, ...)
+{
+ va_list ap;
+ char *tmp = NULL;
+
+ if (!orig_argc)
+ return;
+ va_start (ap, fmt);
+ vasprintf (&tmp, fmt, ap);
+ va_end (ap);
+ if (tmp) {
+ free (proctitle_buffer);
+#if __FreeBSD__ >= 4
+ /* On FreeBSD the process name is prepended automatically */
+ proctitle_buffer = tmp;
+#else
+ /* Otherwise we need to do that manually */
+ asprintf (&proctitle_buffer, "%s: %s", __progname, tmp);
+ if (proctitle_buffer)
+ free (tmp);
+ else
+ proctitle_buffer = tmp;
+#endif
+ mf_proctitle_flush ();
+ }
+}
diff --git a/lib/userprivs.c b/lib/userprivs.c
new file mode 100644
index 0000000..8d13c38
--- /dev/null
+++ b/lib/userprivs.c
@@ -0,0 +1,291 @@
+/* This file is part of Mailfromd.
+ Copyright (C) 2007, 2008 Sergey Poznyakoff
+
+ 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 Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <pwd.h>
+#include <grp.h>
+#include <unistd.h>
+#include <mailutils/assoc.h>
+#include <mailutils/errno.h>
+#include <mailutils/error.h>
+#include <mailutils/errno.h>
+#include <mailutils/nls.h>
+#include <mailutils/list.h>
+#include <mailutils/iterator.h>
+/* FIXME: */
+#include <sysexits.h>
+#include "libpies.h"
+
+int
+get_user_groups (mu_list_t *pgrouplist, const char *user)
+{
+ int rc;
+ struct group *gr;
+ mu_list_t list;
+
+ if (!*pgrouplist)
+ {
+ rc = mu_list_create (pgrouplist);
+ if (rc)
+ {
+ mu_error (_("%s: cannot create list: %s"),
+ "get_user_groups", mu_strerror (rc));
+ return rc;
+ }
+ }
+ list = *pgrouplist;
+ setgrent ();
+ for (rc = 0; rc == 0 && (gr = getgrent ());)
+ {
+ char **p;
+ for (p = gr->gr_mem; *p; p++)
+ if (strcmp (*p, user) == 0)
+ {
+ /* FIXME: Avoid duplicating gids */
+ rc = mu_list_append (list, (void *) gr->gr_gid);
+ if (rc)
+ mu_error (_("%s: cannot append to list: %s"),
+ "get_user_groups", mu_strerror (rc));
+ break;
+ }
+ }
+ endgrent ();
+ return rc;
+}
+
+/* Switch to the given UID/GID */
+int
+switch_to_privs (uid_t uid, gid_t gid, mu_list_t retain_groups)
+{
+ int rc = 0;
+ gid_t *emptygidset;
+ size_t size = 1, j = 1;
+ mu_iterator_t itr;
+
+ if (uid == 0)
+ {
+ mu_error (_("Refusing to run as root"));
+ return 1;
+ }
+
+ /* Create a list of supplementary groups */
+ mu_list_count (retain_groups, &size);
+ size++;
+ emptygidset = xmalloc (size * sizeof emptygidset[0]);
+ emptygidset[0] = gid ? gid : getegid ();
+
+ if (mu_list_get_iterator (retain_groups, &itr) == 0)
+ {
+ for (mu_iterator_first (itr);
+ !mu_iterator_is_done (itr); mu_iterator_next (itr))
+ mu_iterator_current (itr, (void **) (emptygidset + j++));
+ mu_iterator_destroy (&itr);
+ }
+
+ /* Reset group permissions */
+ if (geteuid () == 0 && setgroups (j, emptygidset))
+ {
+ mu_error (_("setgroups(1, %lu) failed: %s"),
+ (unsigned long) emptygidset[0], mu_strerror (errno));
+ rc = 1;
+ }
+ free (emptygidset);
+
+ /* Switch to the user's gid. On some OSes the effective gid must
+ be reset first */
+
+#if defined(HAVE_SETEGID)
+ if ((rc = setegid (gid)) < 0)
+ mu_error (_("setegid(%lu) failed: %s"),
+ (unsigned long) gid, mu_strerror (errno));
+#elif defined(HAVE_SETREGID)
+ if ((rc = setregid (gid, gid)) < 0)
+ mu_error (_("setregid(%lu,%lu) failed: %s"),
+ (unsigned long) gid, (unsigned long) gid, mu_strerror (errno));
+#elif defined(HAVE_SETRESGID)
+ if ((rc = setresgid (gid, gid, gid)) < 0)
+ mu_error (_("setresgid(%lu,%lu,%lu) failed: %s"),
+ (unsigned long) gid,
+ (unsigned long) gid, (unsigned long) gid, mu_strerror (errno));
+#endif
+
+ if (rc == 0 && gid != 0)
+ {
+ if ((rc = setgid (gid)) < 0 && getegid () != gid)
+ mu_error (_("setgid(%lu) failed: %s"),
+ (unsigned long) gid, mu_strerror (errno));
+ if (rc == 0 && getegid () != gid)
+ {
+ mu_error (_("Cannot set effective gid to %lu"),
+ (unsigned long) gid);
+ rc = 1;
+ }
+ }
+
+ /* Now reset uid */
+ if (rc == 0 && uid != 0)
+ {
+ uid_t euid;
+
+ if (setuid (uid)
+ || geteuid () != uid
+ || (getuid () != uid && (geteuid () == 0 || getuid () == 0)))
+ {
+
+#if defined(HAVE_SETREUID)
+ if (geteuid () != uid)
+ {
+ if (setreuid (uid, -1) < 0)
+ {
+ mu_error (_("setreuid(%lu,-1) failed: %s"),
+ (unsigned long) uid, mu_strerror (errno));
+ rc = 1;
+ }
+ if (setuid (uid) < 0)
+ {
+ mu_error (_("second setuid(%lu) failed: %s"),
+ (unsigned long) uid, mu_strerror (errno));
+ rc = 1;
+ }
+ }
+ else
+#endif
+ {
+ mu_error (_("setuid(%lu) failed: %s"),
+ (unsigned long) uid, mu_strerror (errno));
+ rc = 1;
+ }
+ }
+
+ euid = geteuid ();
+ if (uid != 0 && setuid (0) == 0)
+ {
+ mu_error (_("seteuid(0) succeeded when it should not"));
+ rc = 1;
+ }
+ else if (uid != euid && setuid (euid) == 0)
+ {
+ mu_error (_("Cannot drop non-root setuid privileges"));
+ rc = 1;
+ }
+
+ }
+
+ return rc;
+}
+
+
+static int
+translate_item (void *item, void *data)
+{
+ mu_list_t dst = data;
+ struct group *group = getgrnam (item);
+ if (!group)
+ {
+ mu_error (_("Unknown group: %s"), (char *) item);
+ return 1;
+ }
+ return mu_list_append (dst, (void *) group->gr_gid);
+}
+
+static int
+grouplist_translate (mu_list_t * pdst, mu_list_t src)
+{
+ mu_list_t dst;
+ int rc;
+
+ if (!src)
+ return 0;
+ rc = mu_list_create (&dst);
+ if (rc)
+ {
+ mu_error (_("%s: cannot create list: %s"),
+ "grouplist_translate", mu_strerror (rc));
+ return rc;
+ }
+ *pdst = dst;
+ return mu_list_do (src, translate_item, dst);
+}
+
+void
+mf_priv_setup (struct mf_privs *privs)
+{
+ struct passwd *pw;
+ mu_list_t grp = NULL;
+
+ if (!privs || !privs->user)
+ return;
+
+ pw = getpwnam (privs->user);
+ if (!pw)
+ {
+ mu_error (_("No such user: %s"), privs->user);
+ exit (EX_CONFIG);
+ }
+
+ grouplist_translate (&grp, privs->groups);
+ if (privs->allgroups && get_user_groups (&grp, privs->user))
+ exit (EX_CONFIG);
+ if (switch_to_privs (pw->pw_uid, pw->pw_gid, grp))
+ exit (EX_SOFTWARE);
+ mu_list_destroy (&grp);
+}
+
+
+void
+mf_epriv_setup (struct mf_privs *privs)
+{
+ uid_t uid;
+ gid_t gid;
+
+ if (privs)
+ {
+ struct passwd *pw;
+ if (!privs->user)
+ return;
+
+ pw = getpwnam (privs->user);
+ if (!pw)
+ {
+ mu_error (_("No such user: %s"), privs->user);
+ exit (EX_CONFIG);
+ }
+ uid = pw->pw_uid;
+ gid = pw->pw_gid;
+ }
+ else
+ {
+ uid = 0;
+ gid = 0;
+ }
+
+ if (setegid (gid))
+ {
+ mu_error (_("Cannot switch to EGID %lu: %s"),
+ (unsigned long) gid, mu_strerror (errno));
+ exit (EX_USAGE);
+ }
+ if (seteuid (uid))
+ {
+ mu_error (_("Cannot switch to EUID %lu: %s"),
+ (unsigned long) uid, mu_strerror (errno));
+ exit (EX_USAGE);
+ }
+}

Return to:

Send suggestions and report system problems to the System administrator.