changeset 11615:89b7d2d527e8

New module 'idpriv-droptemp'.
author Bruno Haible <bruno@clisp.org>
date Tue, 09 Jun 2009 00:59:34 +0200
parents b3e5d914be7d
children c992e0b3355b
files ChangeLog lib/idpriv-droptemp.c modules/idpriv-droptemp
diffstat 3 files changed, 237 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2009-06-08  Bruno Haible  <bruno@clisp.org>
+
+	New module 'idpriv-droptemp'.
+	* lib/idpriv-droptemp.c: New file.
+	* modules/idpriv-droptemp: New file.
+
 2009-06-08  Bruno Haible  <bruno@clisp.org>
 
 	Tests for module 'idpriv-drop'.
new file mode 100644
--- /dev/null
+++ b/lib/idpriv-droptemp.c
@@ -0,0 +1,204 @@
+/* Dropping uid/gid privileges of the current process temporarily.
+   Copyright (C) 2009 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
+}
new file mode 100644
--- /dev/null
+++ b/modules/idpriv-droptemp
@@ -0,0 +1,27 @@
+Description:
+Drop uid/gid privileges of the current process temporarily.
+
+Files:
+lib/idpriv.h
+lib/idpriv-droptemp.c
+m4/idpriv.m4
+
+Depends-on:
+unistd
+extensions
+
+configure.ac:
+gl_IDPRIV
+
+Makefile.am:
+lib_SOURCES += idpriv-droptemp.c
+
+Include:
+"idpriv.h"
+
+License:
+GPL
+
+Maintainer:
+Bruno Haible
+