diff options
Diffstat (limited to 'gl/idpriv-droptemp.c')
-rw-r--r-- | gl/idpriv-droptemp.c | 204 |
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 | ||
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 <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 | |||
121 | int | ||
122 | idpriv_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 | } | ||