(root)/
man-db-2.12.0/
gl/
lib/
idpriv-droptemp.c
       1  /* Dropping uid/gid privileges of the current process temporarily.
       2     Copyright (C) 2009-2023 Free Software Foundation, Inc.
       3  
       4     This program is free software: you can redistribute it and/or modify
       5     it under the terms of the GNU General Public License as published by
       6     the Free Software Foundation, either version 3 of the License, or
       7     (at your option) any later version.
       8  
       9     This program is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12     GNU General Public License for more details.
      13  
      14     You should have received a copy of the GNU General Public License
      15     along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
      16  
      17  #include <config.h>
      18  
      19  #include "idpriv.h"
      20  
      21  #include <errno.h>
      22  #include <stdlib.h>
      23  #include <sys/types.h>
      24  #include <unistd.h>
      25  
      26  /* The privileged uid and gid that the process had earlier.  */
      27  #if HAVE_GETUID
      28  static int saved_uid = -1;
      29  #endif
      30  #if HAVE_GETGID
      31  static int saved_gid = -1;
      32  #endif
      33  
      34  int
      35  idpriv_temp_drop (void)
      36  {
      37  #if HAVE_GETEUID && HAVE_GETEGID && (HAVE_SETRESUID || HAVE_SETREUID) && (HAVE_SETRESGID || HAVE_SETREGID)
      38    int uid = getuid ();
      39    int gid = getgid ();
      40  
      41    /* Find out about the privileged uid and gid at the first call.  */
      42    if (saved_uid == -1)
      43      saved_uid = geteuid ();
      44    if (saved_gid == -1)
      45      saved_gid = getegid ();
      46  
      47    /* Drop the gid privilege first, because in some cases the gid privilege
      48       cannot be dropped after the uid privilege has been dropped.  */
      49  
      50    /* This is for executables that have the setgid bit set.  */
      51  # if HAVE_SETRESGID /* glibc, FreeBSD, OpenBSD, HP-UX */
      52    if (setresgid (-1, gid, saved_gid) < 0)
      53      return -1;
      54  # else /* Mac OS X, NetBSD, AIX, IRIX, Solaris >= 2.5, OSF/1, Cygwin */
      55    if (setregid (-1, gid) < 0)
      56      return -1;
      57  # endif
      58  
      59    /* This is for executables that have the setuid bit set.  */
      60  # if HAVE_SETRESUID /* glibc, FreeBSD, OpenBSD, HP-UX */
      61    /* See
      62         Hao Chen, David Wagner, Drew Dean: Setuid Demystified
      63         <https://www.usenix.org/legacy/publications/library/proceedings/sec02/full_papers/chen/chen.pdf>
      64       figure 14.  */
      65    if (setresuid (-1, uid, saved_uid) < 0)
      66      return -1;
      67  # else /* Mac OS X, NetBSD, AIX, IRIX, Solaris >= 2.5, OSF/1, Cygwin */
      68    if (setreuid (-1, uid) < 0)
      69      return -1;
      70  # endif
      71  
      72    /* Verify that the privileges have really been dropped.
      73       This verification is here for security reasons.  Doesn't matter if it
      74       takes a couple of system calls.
      75       When the verification fails, it indicates that we need to use different
      76       API in the code above. Therefore 'abort ()', not 'return -1'.  */
      77  # if HAVE_GETRESUID /* glibc, FreeBSD, OpenBSD, HP-UX */
      78    {
      79      uid_t real;
      80      uid_t effective;
      81      uid_t saved;
      82      if (getresuid (&real, &effective, &saved) < 0
      83          || real != uid
      84          || effective != uid
      85          || saved != saved_uid)
      86        abort ();
      87    }
      88  # else
      89  #  if HAVE_GETEUID
      90    if (geteuid () != uid)
      91      abort ();
      92  #  endif
      93    if (getuid () != uid)
      94      abort ();
      95  # endif
      96  # if HAVE_GETRESGID /* glibc, FreeBSD, OpenBSD, HP-UX */
      97    {
      98      uid_t real;
      99      uid_t effective;
     100      uid_t saved;
     101      if (getresgid (&real, &effective, &saved) < 0
     102          || real != gid
     103          || effective != gid
     104          || saved != saved_gid)
     105        abort ();
     106    }
     107  # else
     108  #  if HAVE_GETEGID
     109    if (getegid () != gid)
     110      abort ();
     111  #  endif
     112    if (getgid () != gid)
     113      abort ();
     114  # endif
     115  
     116    return 0;
     117  #else
     118    errno = ENOSYS;
     119    return -1;
     120  #endif
     121  }
     122  
     123  int
     124  idpriv_temp_restore (void)
     125  {
     126  #if HAVE_GETEUID && HAVE_GETEGID && (HAVE_SETRESUID || HAVE_SETREUID) && (HAVE_SETRESGID || HAVE_SETREGID)
     127    int uid = getuid ();
     128    int gid = getgid ();
     129  
     130    if (saved_uid == -1 || saved_gid == -1)
     131      /* Caller error: idpriv_temp_drop was never invoked.  */
     132      abort ();
     133  
     134    /* Acquire the gid privilege last, because in some cases the gid privilege
     135       cannot be acquired before the uid privilege has been acquired.  */
     136  
     137    /* This is for executables that have the setuid bit set.  */
     138  # if HAVE_SETRESUID /* glibc, FreeBSD, OpenBSD, HP-UX */
     139    /* See
     140         Hao Chen, David Wagner, Drew Dean: Setuid Demystified
     141         <https://www.usenix.org/legacy/publications/library/proceedings/sec02/full_papers/chen/chen.pdf>
     142       figure 14.  */
     143    if (setresuid (-1, saved_uid, -1) < 0)
     144      return -1;
     145  # else /* Mac OS X, NetBSD, AIX, IRIX, Solaris >= 2.5, OSF/1, Cygwin */
     146    if (setreuid (-1, saved_uid) < 0)
     147      return -1;
     148  # endif
     149  
     150    /* This is for executables that have the setgid bit set.  */
     151  # if HAVE_SETRESGID /* glibc, FreeBSD, OpenBSD, HP-UX */
     152    if (setresgid (-1, saved_gid, -1) < 0)
     153      return -1;
     154  # else /* Mac OS X, NetBSD, AIX, IRIX, Solaris >= 2.5, OSF/1, Cygwin */
     155    if (setregid (-1, saved_gid) < 0)
     156      return -1;
     157  # endif
     158  
     159    /* Verify that the privileges have really been acquired.
     160       This verification is here for security reasons.  Doesn't matter if it
     161       takes a couple of system calls.
     162       When the verification fails, it indicates that we need to use different
     163       API in the code above. Therefore 'abort ()', not 'return -1'.  */
     164  # if HAVE_GETRESUID /* glibc, FreeBSD, OpenBSD, HP-UX */
     165    {
     166      uid_t real;
     167      uid_t effective;
     168      uid_t saved;
     169      if (getresuid (&real, &effective, &saved) < 0
     170          || real != uid
     171          || effective != saved_uid
     172          || saved != saved_uid)
     173        abort ();
     174    }
     175  # else
     176  #  if HAVE_GETEUID
     177    if (geteuid () != saved_uid)
     178      abort ();
     179  #  endif
     180    if (getuid () != uid)
     181      abort ();
     182  # endif
     183  # if HAVE_GETRESGID /* glibc, FreeBSD, OpenBSD, HP-UX */
     184    {
     185      uid_t real;
     186      uid_t effective;
     187      uid_t saved;
     188      if (getresgid (&real, &effective, &saved) < 0
     189          || real != gid
     190          || effective != saved_gid
     191          || saved != saved_gid)
     192        abort ();
     193    }
     194  # else
     195  #  if HAVE_GETEGID
     196    if (getegid () != saved_gid)
     197      abort ();
     198  #  endif
     199    if (getgid () != gid)
     200      abort ();
     201  # endif
     202  
     203    return 0;
     204  #else
     205    errno = ENOSYS;
     206    return -1;
     207  #endif
     208  }