summaryrefslogtreecommitdiffstats
path: root/gl/idpriv-droptemp.c
diff options
context:
space:
mode:
Diffstat (limited to 'gl/idpriv-droptemp.c')
-rw-r--r--gl/idpriv-droptemp.c204
1 files changed, 204 insertions, 0 deletions
diff --git a/gl/idpriv-droptemp.c b/gl/idpriv-droptemp.c
new file mode 100644
index 00000000..13d1064e
--- /dev/null
+++ b/gl/idpriv-droptemp.c
@@ -0,0 +1,204 @@
1/* Dropping uid/gid privileges of the current process temporarily.
2 Copyright (C) 2009-2013 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 <http://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
28static int saved_uid = -1;
29#endif
30#if HAVE_GETGID
31static int saved_gid = -1;
32#endif
33
34int
35idpriv_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 <http://www.usenix.org/events/sec02/full_papers/chen/chen.pdf>
62 figure 14. */
63 if (setresuid (-1, uid, saved_uid) < 0)
64 return -1;
65# else /* Mac OS X, NetBSD, AIX, IRIX, Solaris >= 2.5, OSF/1, Cygwin */
66 if (setreuid (-1, uid) < 0)
67 return -1;
68# endif
69
70 /* Verify that the privileges have really been dropped.
71 This verification is here for security reasons. Doesn't matter if it
72 takes a couple of system calls.
73 When the verification fails, it indicates that we need to use different
74 API in the code above. Therefore 'abort ()', not 'return -1'. */
75# if HAVE_GETRESUID /* glibc, FreeBSD, OpenBSD, HP-UX */
76 {
77 uid_t real;
78 uid_t effective;
79 uid_t saved;
80 if (getresuid (&real, &effective, &saved) < 0
81 || real != uid
82 || effective != uid
83 || saved != saved_uid)
84 abort ();
85 }
86# else
87# if HAVE_GETEUID
88 if (geteuid () != uid)
89 abort ();
90# endif
91 if (getuid () != uid)
92 abort ();
93# endif
94# if HAVE_GETRESGID /* glibc, FreeBSD, OpenBSD, HP-UX */
95 {
96 uid_t real;
97 uid_t effective;
98 uid_t saved;
99 if (getresgid (&real, &effective, &saved) < 0
100 || real != gid
101 || effective != gid
102 || saved != saved_gid)
103 abort ();
104 }
105# else
106# if HAVE_GETEGID
107 if (getegid () != gid)
108 abort ();
109# endif
110 if (getgid () != gid)
111 abort ();
112# endif
113
114 return 0;
115#else
116 errno = ENOSYS;
117 return -1;
118#endif
119}
120
121int
122idpriv_temp_restore (void)
123{
124#if HAVE_GETEUID && HAVE_GETEGID && (HAVE_SETRESUID || HAVE_SETREUID) && (HAVE_SETRESGID || HAVE_SETREGID)
125 int uid = getuid ();
126 int gid = getgid ();
127
128 if (saved_uid == -1 || saved_gid == -1)
129 /* Caller error: idpriv_temp_drop was never invoked. */
130 abort ();
131
132 /* Acquire the gid privilege last, because in some cases the gid privilege
133 cannot be acquired before the uid privilege has been acquired. */
134
135 /* This is for executables that have the setuid bit set. */
136# if HAVE_SETRESUID /* glibc, FreeBSD, OpenBSD, HP-UX */
137 /* See <http://www.usenix.org/events/sec02/full_papers/chen/chen.pdf>
138 figure 14. */
139 if (setresuid (-1, saved_uid, -1) < 0)
140 return -1;
141# else /* Mac OS X, NetBSD, AIX, IRIX, Solaris >= 2.5, OSF/1, Cygwin */
142 if (setreuid (-1, saved_uid) < 0)
143 return -1;
144# endif
145
146 /* This is for executables that have the setgid bit set. */
147# if HAVE_SETRESGID /* glibc, FreeBSD, OpenBSD, HP-UX */
148 if (setresgid (-1, saved_gid, -1) < 0)
149 return -1;
150# else /* Mac OS X, NetBSD, AIX, IRIX, Solaris >= 2.5, OSF/1, Cygwin */
151 if (setregid (-1, saved_gid) < 0)
152 return -1;
153# endif
154
155 /* Verify that the privileges have really been acquired.
156 This verification is here for security reasons. Doesn't matter if it
157 takes a couple of system calls.
158 When the verification fails, it indicates that we need to use different
159 API in the code above. Therefore 'abort ()', not 'return -1'. */
160# if HAVE_GETRESUID /* glibc, FreeBSD, OpenBSD, HP-UX */
161 {
162 uid_t real;
163 uid_t effective;
164 uid_t saved;
165 if (getresuid (&real, &effective, &saved) < 0
166 || real != uid
167 || effective != saved_uid
168 || saved != saved_uid)
169 abort ();
170 }
171# else
172# if HAVE_GETEUID
173 if (geteuid () != saved_uid)
174 abort ();
175# endif
176 if (getuid () != uid)
177 abort ();
178# endif
179# if HAVE_GETRESGID /* glibc, FreeBSD, OpenBSD, HP-UX */
180 {
181 uid_t real;
182 uid_t effective;
183 uid_t saved;
184 if (getresgid (&real, &effective, &saved) < 0
185 || real != gid
186 || effective != saved_gid
187 || saved != saved_gid)
188 abort ();
189 }
190# else
191# if HAVE_GETEGID
192 if (getegid () != saved_gid)
193 abort ();
194# endif
195 if (getgid () != gid)
196 abort ();
197# endif
198
199 return 0;
200#else
201 errno = ENOSYS;
202 return -1;
203#endif
204}