mountlist: Use Linux code on Android.
[gnulib.git] / lib / idpriv-droptemp.c
blob55ff59104344d553c0088566f6a921ca49ac2564
1 /* Dropping uid/gid privileges of the current process temporarily.
2 Copyright (C) 2009-2019 Free Software Foundation, Inc.
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.
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.
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/>. */
17 #include <config.h>
19 #include "idpriv.h"
21 #include <errno.h>
22 #include <stdlib.h>
23 #include <sys/types.h>
24 #include <unistd.h>
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
34 int
35 idpriv_temp_drop (void)
37 #if HAVE_GETEUID && HAVE_GETEGID && (HAVE_SETRESUID || HAVE_SETREUID) && (HAVE_SETRESGID || HAVE_SETREGID)
38 int uid = getuid ();
39 int gid = getgid ();
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 ();
47 /* Drop the gid privilege first, because in some cases the gid privilege
48 cannot be dropped after the uid privilege has been dropped. */
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
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
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 */
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 ();
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 */
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 ();
107 # else
108 # if HAVE_GETEGID
109 if (getegid () != gid)
110 abort ();
111 # endif
112 if (getgid () != gid)
113 abort ();
114 # endif
116 return 0;
117 #else
118 errno = ENOSYS;
119 return -1;
120 #endif
124 idpriv_temp_restore (void)
126 #if HAVE_GETEUID && HAVE_GETEGID && (HAVE_SETRESUID || HAVE_SETREUID) && (HAVE_SETRESGID || HAVE_SETREGID)
127 int uid = getuid ();
128 int gid = getgid ();
130 if (saved_uid == -1 || saved_gid == -1)
131 /* Caller error: idpriv_temp_drop was never invoked. */
132 abort ();
134 /* Acquire the gid privilege last, because in some cases the gid privilege
135 cannot be acquired before the uid privilege has been acquired. */
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
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
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 */
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 ();
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 */
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 ();
194 # else
195 # if HAVE_GETEGID
196 if (getegid () != saved_gid)
197 abort ();
198 # endif
199 if (getgid () != gid)
200 abort ();
201 # endif
203 return 0;
204 #else
205 errno = ENOSYS;
206 return -1;
207 #endif