diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2008-01-12 15:32:32 +0000 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2008-01-12 15:32:32 +0000 |
commit | 7fec55752e2b2443bb570d62b288ae06dc1976ed (patch) | |
tree | 7abdc77dad1fd7081d6f38303644283a2c52170e | |
parent | 2c5d121399c8f075522c349ecf6ca0b70cbef764 (diff) | |
download | mailfromd-7fec55752e2b2443bb570d62b288ae06dc1976ed.tar.gz mailfromd-7fec55752e2b2443bb570d62b288ae06dc1976ed.tar.bz2 |
* lib/libmf.h: Add switch_to_privs.
* lib/userprivs.c: New file.
* lib/Makefile.am: Add userprivs.c.
* src/gram.y (time_multiplier): Remove forward dcl.
* src/main.c: Move switch_to_privs to lib.
git-svn-id: file:///svnroot/mailfromd/branches/gmach@1559 7a8a7f39-df28-0410-adc6-e0d955640f24
-rw-r--r-- | lib/Makefile.am | 1 | ||||
-rw-r--r-- | lib/libmf.h | 5 | ||||
-rw-r--r-- | lib/userprivs.c | 150 | ||||
-rw-r--r-- | src/gram.y | 1 | ||||
-rw-r--r-- | src/main.c | 119 |
5 files changed, 158 insertions, 118 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am index af44f802..63a922bc 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -25,6 +25,7 @@ libmf_a_SOURCES=\ dict.c\ nls.c\ parsetime.c\ + userprivs.c\ version.c libmf_a_LIBADD=$(LIBOBJS) $(BUILD_SYSLOG_ASYNC) diff --git a/lib/libmf.h b/lib/libmf.h index 9cc68889..c5e43cf3 100644 --- a/lib/libmf.h +++ b/lib/libmf.h @@ -16,6 +16,9 @@ #include <gettext.h> #include <mailutils/types.h> +#include <unistd.h> +#include <pwd.h> +#include <grp.h> #define _(String) gettext(String) #define N_(String) String @@ -28,4 +31,6 @@ void dict_init(mu_assoc_t *dict); char *dict_install(mu_assoc_t dict, const char *name, const char *value); void dict_destroy(mu_assoc_t *dict); char *dict_getsym(void *data, const char *str); +int switch_to_privs (uid_t uid, gid_t gid, mu_list_t retain_groups); + diff --git a/lib/userprivs.c b/lib/userprivs.c new file mode 100644 index 00000000..125210e4 --- /dev/null +++ b/lib/userprivs.c @@ -0,0 +1,150 @@ +/* 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> +#include <xalloc.h> + +/* 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; +} + + @@ -33,7 +33,6 @@ static NODE *alloc_node(enum node_type type, const struct locus *locus); static void free_node(NODE *node); static void set_poll_arg(struct poll_data *poll, int kw, NODE *expr); -static int time_multiplier(const char *, unsigned *, unsigned *); static int codegen(prog_counter_t *pc, NODE *node, int finalize, size_t nautos); static void mark(NODE *node); @@ -1633,122 +1633,6 @@ struct mu_cfg_param mf_cfg_param[] = { /* Auxiliary functions */ -/* Switch to the given UID/GID */ -int -switch_to_privs(uid_t uid, gid_t gid) -{ - 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; -} - void priv_setup() { @@ -1762,7 +1646,8 @@ priv_setup() mu_error(_("No such user: %s"), user); exit(EX_SOFTWARE); } - if (pw && switch_to_privs(pw->pw_uid, pw->pw_gid)) + if (pw && switch_to_privs(pw->pw_uid, pw->pw_gid, + retain_groups)) exit(EX_SOFTWARE); } } |