diff options
author | Colin Watson <cjwatson@debian.org> | 2010-12-19 16:11:13 +0000 |
---|---|---|
committer | Colin Watson <cjwatson@debian.org> | 2010-12-19 16:11:13 +0000 |
commit | f7658f51c254ce16a564d670880d828a00f3a3fc (patch) | |
tree | 5927055ee2e7b194923fa3efef638a6cca670aad /gnulib/lib | |
parent | 2e6a28c3f67527a4a1eb87a26a011bb62d95ee09 (diff) |
* gnulib: Import idpriv-drop and idpriv-droptemp modules.
* configure.ac: Stop checking for seteuid, setreuid, and setresuid.
* lib/security.c (POSIX_SAVED_IDS, SET_EUID, SWAP_UIDS): Remove in
favour of idpriv.h.
(drop_effective_privs): Use idpriv_temp_drop.
(regain_effective_privs): Use idpriv_temp_restore.
(do_system_drop_privs): Use idpriv_drop. Drop saved-IDs case;
avoiding a fork doesn't justify having two code paths.
Diffstat (limited to 'gnulib/lib')
-rw-r--r-- | gnulib/lib/Makefile.am | 18 | ||||
-rw-r--r-- | gnulib/lib/Makefile.in | 70 | ||||
-rw-r--r-- | gnulib/lib/idpriv-drop.c | 129 | ||||
-rw-r--r-- | gnulib/lib/idpriv-droptemp.c | 204 | ||||
-rw-r--r-- | gnulib/lib/idpriv.h | 116 |
5 files changed, 504 insertions, 33 deletions
diff --git a/gnulib/lib/Makefile.am b/gnulib/lib/Makefile.am index 7e792638..4bd09024 100644 --- a/gnulib/lib/Makefile.am +++ b/gnulib/lib/Makefile.am @@ -9,7 +9,7 @@ # the same distribution terms as the rest of that program. # # Generated by gnulib-tool. -# Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=gnulib/lib --m4-base=gnulib/m4 --po-base=gnulib/po --doc-base=doc --tests-base=tests --aux-dir=tools --libtool --macro-prefix=gl --po-domain=man-db argp canonicalize dirname error fnmatch-gnu getopt-gnu gettext glob lib-ignore localcharset lock minmax mkdtemp mkstemp regex rename setenv sigaction signal sigprocmask strerror strsep unsetenv xalloc xgetcwd xstrndup xvasprintf +# Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=gnulib/lib --m4-base=gnulib/m4 --po-base=gnulib/po --doc-base=doc --tests-base=tests --aux-dir=tools --libtool --macro-prefix=gl --po-domain=man-db argp canonicalize dirname error fnmatch-gnu getopt-gnu gettext glob idpriv-drop idpriv-droptemp lib-ignore localcharset lock minmax mkdtemp mkstemp regex rename setenv sigaction signal sigprocmask strerror strsep unsetenv xalloc xgetcwd xstrndup xvasprintf AUTOMAKE_OPTIONS = 1.5 gnits subdir-objects @@ -642,6 +642,22 @@ EXTRA_DIST += $(top_srcdir)/tools/config.rpath ## end gnulib module havelib +## begin gnulib module idpriv-drop + +libgnu_la_SOURCES += idpriv-drop.c + +EXTRA_DIST += idpriv.h + +## end gnulib module idpriv-drop + +## begin gnulib module idpriv-droptemp + +libgnu_la_SOURCES += idpriv-droptemp.c + +EXTRA_DIST += idpriv.h + +## end gnulib module idpriv-droptemp + ## begin gnulib module intprops diff --git a/gnulib/lib/Makefile.in b/gnulib/lib/Makefile.in index bf012ce1..a1f8eb86 100644 --- a/gnulib/lib/Makefile.in +++ b/gnulib/lib/Makefile.in @@ -24,7 +24,7 @@ # the same distribution terms as the rest of that program. # # Generated by gnulib-tool. -# Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=gnulib/lib --m4-base=gnulib/m4 --po-base=gnulib/po --doc-base=doc --tests-base=tests --aux-dir=tools --libtool --macro-prefix=gl --po-domain=man-db argp canonicalize dirname error fnmatch-gnu getopt-gnu gettext glob lib-ignore localcharset lock minmax mkdtemp mkstemp regex rename setenv sigaction signal sigprocmask strerror strsep unsetenv xalloc xgetcwd xstrndup xvasprintf +# Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=gnulib/lib --m4-base=gnulib/m4 --po-base=gnulib/po --doc-base=doc --tests-base=tests --aux-dir=tools --libtool --macro-prefix=gl --po-domain=man-db argp canonicalize dirname error fnmatch-gnu getopt-gnu gettext glob idpriv-drop idpriv-droptemp lib-ignore localcharset lock minmax mkdtemp mkstemp regex rename setenv sigaction signal sigprocmask strerror strsep unsetenv xalloc xgetcwd xstrndup xvasprintf @@ -104,6 +104,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/man-bdb.m4 \ $(top_srcdir)/gnulib/m4/gnulib-comp.m4 \ $(top_srcdir)/gnulib/m4/hash.m4 \ $(top_srcdir)/gnulib/m4/iconv.m4 \ + $(top_srcdir)/gnulib/m4/idpriv.m4 \ $(top_srcdir)/gnulib/m4/include_next.m4 \ $(top_srcdir)/gnulib/m4/inline.m4 \ $(top_srcdir)/gnulib/m4/intlmacosx.m4 \ @@ -222,9 +223,10 @@ am_libgnu_la_OBJECTS = areadlink-with-size.lo argp-ba.lo argp-eexst.lo \ argp-fmtstream.lo argp-fs-xinl.lo argp-help.lo argp-parse.lo \ argp-pin.lo argp-pv.lo argp-pvh.lo argp-xinl.lo close-hook.lo \ exitfail.lo file-set.lo hash-pjw.lo hash-triple.lo \ - localcharset.lo glthread/lock.lo malloca.lo openat-die.lo \ - strnlen1.lo glthread/threadlib.lo xalloc-die.lo xstrndup.lo \ - xvasprintf.lo xasprintf.lo + idpriv-drop.lo idpriv-droptemp.lo localcharset.lo \ + glthread/lock.lo malloca.lo openat-die.lo strnlen1.lo \ + glthread/threadlib.lo xalloc-die.lo xstrndup.lo xvasprintf.lo \ + xasprintf.lo libgnu_la_OBJECTS = $(am_libgnu_la_OBJECTS) AM_V_lt = $(am__v_lt_$(V)) am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) @@ -1066,30 +1068,31 @@ EXTRA_DIST = alloca.c alloca.in.h areadlink.h \ getcwd.c getdtablesize.c getlogin_r.c getopt.c getopt.in.h \ getopt1.c getopt_int.h $(top_srcdir)/tools/config.rpath \ gettimeofday.c glob-libc.h glob.c glob.in.h hash.c hash.h \ - hash-triple.h $(top_srcdir)/tools/config.rpath intprops.h \ - langinfo.in.h lchown.c config.charset ref-add.sin ref-del.sin \ - lstat.c malloc.c malloc.c malloca.h malloca.valgrind mbrtowc.c \ - mbsinit.c mbsrtowcs-state.c mbsrtowcs.c memchr.c \ - memchr.valgrind mempcpy.c memrchr.c mkdir.c mkdtemp.c \ - mkstemp.c nl_langinfo.c open.c at-func.c fchmodat.c fchownat.c \ - fstatat.c mkdirat.c openat-priv.h openat-proc.c openat.c \ - openat.h unlinkat.c pathmax.h rawmemchr.c rawmemchr.valgrind \ - readlink.c realloc.c regcomp.c regex.c regex.h \ - regex_internal.c regex_internal.h regexec.c rename.c rmdir.c \ - same.c same.h same-inode.h save-cwd.c save-cwd.h setenv.c \ - sig-handler.h sigaction.c signal.in.h sigprocmask.c sleep.c \ - stat.c stdarg.in.h stdbool.in.h stddef.in.h stdint.in.h \ - stdio-write.c stdio.in.h stdlib.in.h strcasecmp.c \ - strncasecmp.c strchrnul.c strchrnul.valgrind strdup.c streq.h \ - strerror.c string.in.h strings.in.h strndup.c strnlen.c \ - strsep.c sys_stat.in.h sys_time.in.h sysexits.in.h tempname.c \ - tempname.h $(top_srcdir)/tools/config.rpath time.in.h \ - unistd.in.h dup-safer.c fd-safer.c pipe-safer.c unistd--.h \ - unistd-safer.h unlink.c unsetenv.c asnprintf.c float+.h \ - printf-args.c printf-args.h printf-parse.c printf-parse.h \ - vasnprintf.c vasnprintf.h asprintf.c vasprintf.c vsnprintf.c \ - $(top_srcdir)/tools/warn-on-use.h wchar.in.h wcrtomb.c \ - wctype.in.h xalloc.h xmalloc.c xgetcwd.c xgetcwd.h xalloc.h + hash-triple.h $(top_srcdir)/tools/config.rpath idpriv.h \ + idpriv.h intprops.h langinfo.in.h lchown.c config.charset \ + ref-add.sin ref-del.sin lstat.c malloc.c malloc.c malloca.h \ + malloca.valgrind mbrtowc.c mbsinit.c mbsrtowcs-state.c \ + mbsrtowcs.c memchr.c memchr.valgrind mempcpy.c memrchr.c \ + mkdir.c mkdtemp.c mkstemp.c nl_langinfo.c open.c at-func.c \ + fchmodat.c fchownat.c fstatat.c mkdirat.c openat-priv.h \ + openat-proc.c openat.c openat.h unlinkat.c pathmax.h \ + rawmemchr.c rawmemchr.valgrind readlink.c realloc.c regcomp.c \ + regex.c regex.h regex_internal.c regex_internal.h regexec.c \ + rename.c rmdir.c same.c same.h same-inode.h save-cwd.c \ + save-cwd.h setenv.c sig-handler.h sigaction.c signal.in.h \ + sigprocmask.c sleep.c stat.c stdarg.in.h stdbool.in.h \ + stddef.in.h stdint.in.h stdio-write.c stdio.in.h stdlib.in.h \ + strcasecmp.c strncasecmp.c strchrnul.c strchrnul.valgrind \ + strdup.c streq.h strerror.c string.in.h strings.in.h strndup.c \ + strnlen.c strsep.c sys_stat.in.h sys_time.in.h sysexits.in.h \ + tempname.c tempname.h $(top_srcdir)/tools/config.rpath \ + time.in.h unistd.in.h dup-safer.c fd-safer.c pipe-safer.c \ + unistd--.h unistd-safer.h unlink.c unsetenv.c asnprintf.c \ + float+.h printf-args.c printf-args.h printf-parse.c \ + printf-parse.h vasnprintf.c vasnprintf.h asprintf.c \ + vasprintf.c vsnprintf.c $(top_srcdir)/tools/warn-on-use.h \ + wchar.in.h wcrtomb.c wctype.in.h xalloc.h xmalloc.c xgetcwd.c \ + xgetcwd.h xalloc.h # The BUILT_SOURCES created by this Makefile snippet are not used via #include # statements but through direct file reference. Therefore this snippet must be @@ -1140,10 +1143,11 @@ libgnu_la_SOURCES = areadlink-with-size.c argp.h argp-ba.c \ argp-help.c argp-namefrob.h argp-parse.c argp-pin.c argp-pv.c \ argp-pvh.c argp-xinl.c bitrotate.h close-hook.c exitfail.c \ file-set.c gettext.h hash-pjw.h hash-pjw.c hash-triple.c \ - localcharset.h localcharset.c glthread/lock.h glthread/lock.c \ - malloca.c minmax.h openat-die.c size_max.h strnlen1.h \ - strnlen1.c glthread/threadlib.c verify.h xalloc-die.c xsize.h \ - xstrndup.h xstrndup.c xvasprintf.h xvasprintf.c xasprintf.c + idpriv-drop.c idpriv-droptemp.c localcharset.h localcharset.c \ + glthread/lock.h glthread/lock.c malloca.c minmax.h \ + openat-die.c size_max.h strnlen1.h strnlen1.c \ + glthread/threadlib.c verify.h xalloc-die.c xsize.h xstrndup.h \ + xstrndup.c xvasprintf.h xvasprintf.c xasprintf.c libgnu_la_LIBADD = $(gl_LTLIBOBJS) @LTALLOCA@ libgnu_la_DEPENDENCIES = $(gl_LTLIBOBJS) @LTALLOCA@ EXTRA_libgnu_la_SOURCES = alloca.c btowc.c canonicalize.c \ @@ -1296,6 +1300,8 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hash-pjw.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hash-triple.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hash.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/idpriv-drop.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/idpriv-droptemp.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lchown.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/localcharset.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lstat.Plo@am__quote@ diff --git a/gnulib/lib/idpriv-drop.c b/gnulib/lib/idpriv-drop.c new file mode 100644 index 00000000..30ce5a4f --- /dev/null +++ b/gnulib/lib/idpriv-drop.c @@ -0,0 +1,129 @@ +/* Dropping uid/gid privileges of the current process permanently. + Copyright (C) 2009, 2010 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 of the License, 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 <config.h> + +#include "idpriv.h" + +#include <stdlib.h> +#include <sys/types.h> +#include <unistd.h> + +int +idpriv_drop (void) +{ +#if HAVE_GETUID + int uid = getuid (); +#endif +#if HAVE_GETGID + int gid = getgid (); +#endif + + /* Drop the gid privilege first, because in some cases the gid privilege + cannot be dropped after the uid privilege has been dropped. */ + + /* This is for executables that have the setgid bit set. */ +#if HAVE_SETRESGID /* glibc, FreeBSD, OpenBSD, HP-UX */ + /* This code is needed: In particular, on HP-UX 11.11, setregid (gid, gid) + may leave the saved gid as 0. See also the comment below regarding + setresuid. */ + if (setresgid (gid, gid, gid) < 0) + return -1; +#elif HAVE_SETREGID /* MacOS X, NetBSD, AIX, IRIX, Solaris, OSF/1, Cygwin */ + if (setregid (gid, gid) < 0) + return -1; +#elif HAVE_SETEGID /* Solaris 2.4 */ + if (setegid (gid) < 0) + return -1; +#endif + + /* This is for executables that have the setuid bit set. */ +#if HAVE_SETRESUID /* glibc, FreeBSD, OpenBSD, HP-UX */ + /* On systems which have setresuid(), we use it instead of setreuid(), + because + <http://www.usenix.org/events/sec02/full_papers/chen/chen.pdf> + says about setreuid(): "The rule by which the saved uid id is modified + is complicated." Similarly, <http://unixpapa.com/incnote/setuid.html> + says about setreuid(): "What exactly happens to the saved UID when this + is used seems to vary a lot." */ + if (setresuid (uid, uid, uid) < 0) + return -1; +#elif HAVE_SETREUID /* MacOS X, NetBSD, AIX, IRIX, Solaris, OSF/1, Cygwin */ + if (setreuid (uid, uid) < 0) + return -1; +#elif HAVE_SETEUID /* Solaris 2.4 */ + if (seteuid (uid) < 0) + return -1; +#endif + + /* Verify that the privileges have really been dropped. + This verification is here for security reasons. Doesn't matter if it + takes a couple of system calls. + On Solaris (which has saved uids and gids but no getresuid, getresgid + functions), we could read /proc/<pid>/cred and verify the saved uid and + gid found there. But it's not clear to me when to interpret the file as a + 'prcred_t' and when as a 'prcred32_t'. + <http://www.usenix.org/events/sec02/full_papers/chen/chen.pdf> + section 8.1.3 also recommends to use a setreuid call as a probe, but + this call would unexpectedly succeed (and the verification thus fail) + on Linux if the process has the CAP_SETUID capability. + When the verification fails, it indicates that we need to use different + API in the code above. Therefore 'abort ()', not 'return -1'. */ +#if HAVE_GETRESUID /* glibc, FreeBSD, OpenBSD, HP-UX */ + { + uid_t real; + uid_t effective; + uid_t saved; + if (getresuid (&real, &effective, &saved) < 0 + || real != uid + || effective != uid + || saved != uid) + abort (); + } +#else +# if HAVE_GETEUID + if (geteuid () != uid) + abort (); +# endif +# if HAVE_GETUID + if (getuid () != uid) + abort (); +# endif +#endif +#if HAVE_GETRESGID /* glibc, FreeBSD, OpenBSD, HP-UX */ + { + gid_t real; + gid_t effective; + gid_t saved; + if (getresgid (&real, &effective, &saved) < 0 + || real != gid + || effective != gid + || saved != gid) + abort (); + } +#else +# if HAVE_GETEGID + if (getegid () != gid) + abort (); +# endif +# if HAVE_GETGID + if (getgid () != gid) + abort (); +# endif +#endif + + return 0; +} diff --git a/gnulib/lib/idpriv-droptemp.c b/gnulib/lib/idpriv-droptemp.c new file mode 100644 index 00000000..1c19c13d --- /dev/null +++ b/gnulib/lib/idpriv-droptemp.c @@ -0,0 +1,204 @@ +/* Dropping uid/gid privileges of the current process temporarily. + Copyright (C) 2009, 2010 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 of the License, 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 <config.h> + +#include "idpriv.h" + +#include <errno.h> +#include <stdlib.h> +#include <sys/types.h> +#include <unistd.h> + +/* The privileged uid and gid that the process had earlier. */ +#if HAVE_GETUID +static int saved_uid = -1; +#endif +#if HAVE_GETGID +static int saved_gid = -1; +#endif + +int +idpriv_temp_drop (void) +{ +#if HAVE_GETEUID && HAVE_GETEGID && (HAVE_SETRESUID || HAVE_SETREUID) && (HAVE_SETRESGID || HAVE_SETREGID) + int uid = getuid (); + int gid = getgid (); + + /* Find out about the privileged uid and gid at the first call. */ + if (saved_uid == -1) + saved_uid = geteuid (); + if (saved_gid == -1) + saved_gid = getegid (); + + /* Drop the gid privilege first, because in some cases the gid privilege + cannot be dropped after the uid privilege has been dropped. */ + + /* This is for executables that have the setgid bit set. */ +# if HAVE_SETRESGID /* glibc, FreeBSD, OpenBSD, HP-UX */ + if (setresgid (-1, gid, saved_gid) < 0) + return -1; +# else /* MacOS X, NetBSD, AIX, IRIX, Solaris >= 2.5, OSF/1, Cygwin */ + if (setregid (-1, gid) < 0) + return -1; +# endif + + /* This is for executables that have the setuid bit set. */ +# if HAVE_SETRESUID /* glibc, FreeBSD, OpenBSD, HP-UX */ + /* See <http://www.usenix.org/events/sec02/full_papers/chen/chen.pdf> + figure 14. */ + if (setresuid (-1, uid, saved_uid) < 0) + return -1; +# else /* MacOS X, NetBSD, AIX, IRIX, Solaris >= 2.5, OSF/1, Cygwin */ + if (setreuid (-1, uid) < 0) + return -1; +# endif + + /* Verify that the privileges have really been dropped. + This verification is here for security reasons. Doesn't matter if it + takes a couple of system calls. + When the verification fails, it indicates that we need to use different + API in the code above. Therefore 'abort ()', not 'return -1'. */ +# if HAVE_GETRESUID /* glibc, FreeBSD, OpenBSD, HP-UX */ + { + uid_t real; + uid_t effective; + uid_t saved; + if (getresuid (&real, &effective, &saved) < 0 + || real != uid + || effective != uid + || saved != saved_uid) + abort (); + } +# else +# if HAVE_GETEUID + if (geteuid () != uid) + abort (); +# endif + if (getuid () != uid) + abort (); +# endif +# if HAVE_GETRESGID /* glibc, FreeBSD, OpenBSD, HP-UX */ + { + uid_t real; + uid_t effective; + uid_t saved; + if (getresgid (&real, &effective, &saved) < 0 + || real != gid + || effective != gid + || saved != saved_gid) + abort (); + } +# else +# if HAVE_GETEGID + if (getegid () != gid) + abort (); +# endif + if (getgid () != gid) + abort (); +# endif + + return 0; +#else + errno = ENOSYS; + return -1; +#endif +} + +int +idpriv_temp_restore (void) +{ +#if HAVE_GETEUID && HAVE_GETEGID && (HAVE_SETRESUID || HAVE_SETREUID) && (HAVE_SETRESGID || HAVE_SETREGID) + int uid = getuid (); + int gid = getgid (); + + if (saved_uid == -1 || saved_gid == -1) + /* Caller error: idpriv_temp_drop was never invoked. */ + abort (); + + /* Acquire the gid privilege last, because in some cases the gid privilege + cannot be acquired before the uid privilege has been acquired. */ + + /* This is for executables that have the setuid bit set. */ +# if HAVE_SETRESUID /* glibc, FreeBSD, OpenBSD, HP-UX */ + /* See <http://www.usenix.org/events/sec02/full_papers/chen/chen.pdf> + figure 14. */ + if (setresuid (-1, saved_uid, -1) < 0) + return -1; +# else /* MacOS X, NetBSD, AIX, IRIX, Solaris >= 2.5, OSF/1, Cygwin */ + if (setreuid (-1, saved_uid) < 0) + return -1; +# endif + + /* This is for executables that have the setgid bit set. */ +# if HAVE_SETRESGID /* glibc, FreeBSD, OpenBSD, HP-UX */ + if (setresgid (-1, saved_gid, -1) < 0) + return -1; +# else /* MacOS X, NetBSD, AIX, IRIX, Solaris >= 2.5, OSF/1, Cygwin */ + if (setregid (-1, saved_gid) < 0) + return -1; +# endif + + /* Verify that the privileges have really been acquired. + This verification is here for security reasons. Doesn't matter if it + takes a couple of system calls. + When the verification fails, it indicates that we need to use different + API in the code above. Therefore 'abort ()', not 'return -1'. */ +# if HAVE_GETRESUID /* glibc, FreeBSD, OpenBSD, HP-UX */ + { + uid_t real; + uid_t effective; + uid_t saved; + if (getresuid (&real, &effective, &saved) < 0 + || real != uid + || effective != saved_uid + || saved != saved_uid) + abort (); + } +# else +# if HAVE_GETEUID + if (geteuid () != saved_uid) + abort (); +# endif + if (getuid () != uid) + abort (); +# endif +# if HAVE_GETRESGID /* glibc, FreeBSD, OpenBSD, HP-UX */ + { + uid_t real; + uid_t effective; + uid_t saved; + if (getresgid (&real, &effective, &saved) < 0 + || real != gid + || effective != saved_gid + || saved != saved_gid) + abort (); + } +# else +# if HAVE_GETEGID + if (getegid () != saved_gid) + abort (); +# endif + if (getgid () != gid) + abort (); +# endif + + return 0; +#else + errno = ENOSYS; + return -1; +#endif +} diff --git a/gnulib/lib/idpriv.h b/gnulib/lib/idpriv.h new file mode 100644 index 00000000..eb4d0517 --- /dev/null +++ b/gnulib/lib/idpriv.h @@ -0,0 +1,116 @@ +/* Dropping uid/gid privileges of the current process. + Copyright (C) 2009, 2010 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 of the License, 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/>. */ + +#ifndef _IDPRIV_H +#define _IDPRIV_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* This module allows programs which are installed with setuid or setgid bit + (and which therefore initially run with an effective user id or group id + different from the one of the current user) to drop their uid or gid + privilege, either permanently or temporarily. + + It is absolutely necessary to minimize the amount of code that is running + with escalated privileges (e.g. with effective uid = root). The reason is + that any bug or exploit in a part of a program that is running with + escalated privileges is a security vulnerability that - upon discovery - + puts the users in danger and requires immediate fixing. Then consider that + there's a bug every 10 or 20 lines of code on average... + + For programs that temporarily drop privileges but have the ability to + restore them later, there are additionally the dangers that + - Any bug in the non-privileged part of the program may be used to + create invalid data structures that will trigger security + vulnerabilities in the privileged part of the program. + - Code execution exploits in the non-privileged part of the program may + be used to invoke the function that restores high privileges and then + execute additional arbitrary code. + + 1) The usual, and reasonably safe, way to minimize the amount of code + running with privileges is to create a separate executable, with setuid + or setgid bit, that contains only code for the tasks that require + privileges (and,of course, strict checking of the arguments, so that the + program cannot be abused). The main program is installed without setuid + or setgid bit. + + 2) A less safe way is to do some privileged tasks at the beginning of the + program's run, and drop privileges permanently as soon as possible. + + Note: There may still be security issues if the privileged task puts + sensitive data into the process memory or opens communication channels + to restricted facilities. + + 3) The most unsafe way is to drop privileges temporarily for most of the + main program but to re-enable them for the duration of privileged tasks. + + As explained above, this approach has uncontrollable dangers for + security. + + This approach is normally not usable in multithreaded programs, because + you cannot know what kind of system calls the other threads could be + doing during the time the privileges are enabled. + + With approach 1, you don't need gnulib modules. + With approach 2, you need the gnulib module 'idpriv-drop'. + With approach 3, you need the gnulib module 'idpriv-droptemp'. But really, + you should better stay away from this approach. + */ + +/* For more in-depth discussion of these topics, see the papers/articles + * Hao Chen, David Wagner, Drew Dean: Setuid Demystified + <http://www.usenix.org/events/sec02/full_papers/chen/chen.pdf> + * Dan Tsafrir, Dilma da Silva, David Wagner: The Murky Issue of Changing + Process Identity: Revising "Setuid Demystified" + <http://www.eecs.berkeley.edu/~daw/papers/setuid-login08b.pdf> + <http://code.google.com/p/change-process-identity/> + * Dhruv Mohindra: Observe correct revocation order while relinquishing + privileges + <https://www.securecoding.cert.org/confluence/display/seccode/POS36-C.+Observe+correct+revocation+order+while+relinquishing+privileges> + */ + + +/* For approach 2. */ + +/* Drop the uid and gid privileges of the current process. + Return 0 if successful, or -1 with errno set upon failure. The recommended + handling of failure is to terminate the process. */ +extern int idpriv_drop (void); + + +/* For approach 3. */ + +/* Drop the uid and gid privileges of the current process in a way that allows + them to be restored later. + Return 0 if successful, or -1 with errno set upon failure. The recommended + handling of failure is to terminate the process. */ +extern int idpriv_temp_drop (void); + +/* Restore the uid and gid privileges of the current process. + Return 0 if successful, or -1 with errno set upon failure. The recommended + handling of failure is to not perform the actions that require the escalated + privileges. */ +extern int idpriv_temp_restore (void); + + +#ifdef __cplusplus +} +#endif + + +#endif /* _IDPRIV_H */ |