view lib/idpriv-droptemp.c @ 14379:2330aac2ae54

maint: adjust cpp indentation to reflect nesting depth I.e., in a block of code that begins with an unnested "#if", put one space between the "#" in column 1 and following token. For example, -#include <sys/vfs.h> +# include <sys/vfs.h> Do this only in .c files that are part of a module I maintain. * lib/linkat.c: Filter through cppi. * lib/nanosleep.c: Likewise. * lib/openat.c: Likewise. * lib/openat-die.c: Likewise. * lib/dup3.c: Likewise. * lib/fchownat.c: Likewise. * lib/flock.c: Likewise. * lib/fsync.c: Likewise. * lib/fts.c: Likewise. * lib/getpass.c: Likewise. * lib/gettimeofday.c: Likewise. * lib/userspec.c: Likewise. * Makefile (sc_cpp_indent_check): New rule, to check this.
author Jim Meyering <meyering@redhat.com>
date Sun, 20 Feb 2011 23:02:43 +0100
parents 97fc9a21a8fb
children 8250f2777afc
line wrap: on
line source

/* Dropping uid/gid privileges of the current process temporarily.
   Copyright (C) 2009-2011 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
}