idpriv-droptemp.c 5.6 KB

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