diff options
Diffstat (limited to 'lib/security.c')
-rw-r--r-- | lib/security.c | 177 |
1 files changed, 177 insertions, 0 deletions
diff --git a/lib/security.c b/lib/security.c new file mode 100644 index 0000000..92cccc3 --- /dev/null +++ b/lib/security.c @@ -0,0 +1,177 @@ +/* + * security.c: Routines to aid secure uid operations + * + * Copyright (C) 1994, 1995 Graeme W. Wilford. (Wilf.) + * Copyright (C) 2001, 2003, 2004, 2007, 2010, 2011 Colin Watson. + * + * This file is part of man-db. + * + * man-db 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 2 of the License, or + * (at your option) any later version. + * + * man-db 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 man-db; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Mon Aug 8 20:35:30 BST 1994 Wilf. (G.Wilford@ee.surrey.ac.uk) + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include <stdbool.h> +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <assert.h> +#include <errno.h> +#include <sys/types.h> + +#include "attribute.h" +#include "error.h" +#include "gettext.h" +#define _(String) gettext (String) + +#include "manconfig.h" + +#include "cleanup.h" +#include "debug.h" +#include "fatal.h" +#include "security.h" + +#ifdef MAN_OWNER + + /* + * This is the name of the user that the preformatted man pages belong to. + * If you are running man as a setuid program, you should make sure + * that all of the cat pages and the directories that + * they live in are writeable by this user. + */ + +# include <pwd.h> +# include <unistd.h> + +# include "idpriv.h" + +uid_t ruid; /* initial real user id */ +uid_t euid; /* initial effective user id */ +uid_t uid; /* current euid */ +gid_t rgid; /* initial real group id */ +gid_t egid; /* initial effective group id */ +gid_t gid; /* current egid */ + +static struct passwd *man_owner; + +/* Keep a count of how many times we've dropped privileges, and only regain + * them if regain_effective_privs() is called an equal number of times. + */ +static int priv_drop_count = 0; + +static void gripe_set_euid (void) +{ + fatal (errno, _("can't set effective uid")); +} + +#endif /* MAN_OWNER */ + +void init_security (void) +{ +#ifdef MAN_OWNER + ruid = getuid (); + uid = euid = geteuid (); + debug ("ruid=%d, euid=%d\n", (int) ruid, (int) euid); + rgid = getgid (); + gid = egid = getegid (); + debug ("rgid=%d, egid=%d\n", (int) rgid, (int) egid); + priv_drop_count = 0; + drop_effective_privs (); +#endif /* MAN_OWNER */ +} + +bool ATTRIBUTE_PURE running_setuid (void) +{ +#ifdef MAN_OWNER + return ruid != euid; +#else /* !MAN_OWNER */ + return false; +#endif +} + +#ifdef MAN_OWNER +/* Return a pointer to the password entry structure for MAN_OWNER. This + * structure will be statically stored. + */ +struct passwd *get_man_owner (void) +{ + if (man_owner) + return man_owner; + + man_owner = getpwnam (MAN_OWNER); + if (!man_owner) + error (FAIL, 0, _("the setuid man user \"%s\" does not exist"), + MAN_OWNER); + assert (man_owner); + return man_owner; +} +#endif /* MAN_OWNER */ + +/* + * function to gain user privs by either (a) dropping effective privs + * completely (saved ids) or (b) reversing euid w/ uid. + * Ignore if superuser. + */ +void drop_effective_privs (void) +{ +#ifdef MAN_OWNER + if (uid != ruid) { + debug ("drop_effective_privs()\n"); + if (idpriv_temp_drop ()) + gripe_set_euid (); + uid = ruid; + gid = rgid; + } + + priv_drop_count++; +#endif /* MAN_OWNER */ +} + +/* + * function to (re)gain setuid privs by (a) setting euid from suid or (b) + * (re)reversing uid w/ euid. Ignore if superuser. + */ +void regain_effective_privs (void) +{ +#ifdef MAN_OWNER + if (priv_drop_count) { + priv_drop_count--; + if (priv_drop_count) + return; + } + + if (uid != euid) { + debug ("regain_effective_privs()\n"); + if (idpriv_temp_restore ()) + gripe_set_euid (); + + uid = euid; + gid = egid; + } +#endif /* MAN_OWNER */ +} + +/* Pipeline command pre-exec hook to permanently drop privileges. */ +void drop_privs (void *data MAYBE_UNUSED) +{ +#ifdef MAN_OWNER + if (idpriv_drop ()) + gripe_set_euid (); +#endif /* MAN_OWNER */ +} |