From 989a5bbb74c3620abaa2191ce2c4f8d5968dbf0a Mon Sep 17 00:00:00 2001 From: Sergey Poznyakoff Date: Tue, 15 Sep 2009 10:40:29 +0300 Subject: Branch off from the Mailfromd project into a separate repository. --- lib/Makefile.am | 33 +++++++ lib/config.c | 115 ++++++++++++++++++++++ lib/intprops.h | 79 +++++++++++++++ lib/libpies.h | 70 ++++++++++++++ lib/nls.c | 34 +++++++ lib/parsetime.c | 109 +++++++++++++++++++++ lib/proctitle.c | 164 +++++++++++++++++++++++++++++++ lib/userprivs.c | 291 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 895 insertions(+) create mode 100644 lib/Makefile.am create mode 100644 lib/config.c create mode 100644 lib/intprops.h create mode 100644 lib/libpies.h create mode 100644 lib/nls.c create mode 100644 lib/parsetime.c create mode 100644 lib/proctitle.c create mode 100644 lib/userprivs.c (limited to 'lib') 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 . + +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 . */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + + +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 + +/* 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 . */ + +#include +#include +#include +#include +#include + + +#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 . */ + +#ifdef HAVE_CONFIG_H +# include +#endif +#include +#include +#include + +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 . */ + +#ifdef HAVE_CONFIG_H +# include +#endif +#include +#include +#include +#include + +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 . */ + +#ifdef HAVE_CONFIG_H +# include +#endif +#include +#include +#include +#include +#include +#include +#if MF_PROCTITLE_TYPE == MF_PROCTITLE_PSTAT +# include +#elif MF_PROCTITLE_TYPE == MF_PROCTITLE_PSSTRINGS +# include +# include +# include +# include +# include +#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 . */ + +#ifdef HAVE_CONFIG_H +# include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +/* FIXME: */ +#include +#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); + } +} -- cgit v1.2.1