1 /* @(#)setuid.c 1.23 15/09/15 Copyright 1998,1999,2004 Heiko Eissfeldt, Copyright 2004-2011 J. Schilling */
2 #include "config.h"
3 #ifndef lint
4 static UConst char sccsid[] =
5 "@(#)setuid.c 1.23 15/09/15 Copyright 1998,1999,2004 Heiko Eissfeldt, Copyright 2004-2011 J. Schilling";
6
7 #endif
8 /*
9 * Security functions
10 *
11 * If these functions fail, it is because there was an installation error
12 * or a programming error, and we can't be sure about what privileges
13 * we do or do not have. This means we might not be able to recover
14 * the privileges we need to fix anything that may be broken (e.g. the
15 * CDDA state of some interface types), and we may in fact do something
16 * quite dangerous (like write to the WAV file as root).
17 *
18 * In any case, it is unsafe to do anything but exit *now*. Ideally we'd
19 * kill -9 our process group too, just to be sure. Root privileges are not
20 * something you want floating around at random in user-level applications.
21 *
22 * If any signal handlers or child processes are introduced into this
23 * program, it will be necessary to call dontneedroot() or neverneedroot()
24 * on entry, respectively; otherwise, it will be possible to trick
25 * the program into executing the signal handler or child process with
26 * root privileges by sending signals at the right time.
27 */
28 /*
29 * The contents of this file are subject to the terms of the
30 * Common Development and Distribution License, Version 1.0 only
31 * (the "License"). You may not use this file except in compliance
32 * with the License.
33 *
34 * See the file CDDL.Schily.txt in this distribution for details.
35 * A copy of the CDDL is also available via the Internet at
36 * http://www.opensource.org/licenses/cddl1.txt
37 *
38 * When distributing Covered Code, include this CDDL HEADER in each
39 * file and include the License file CDDL.Schily.txt from this distribution.
40 */
41
42 #include "config.h"
43 #include <schily/unistd.h>
44 #include <schily/stdio.h>
45 #include <schily/stdlib.h>
46 #include <schily/schily.h>
47 #include <schily/nlsdefs.h>
48
49 #include "exitcodes.h"
50 #include "setuid.h"
51
52 /*#undef DEBUG*/
53 /*#define DEBUG*/
54
55 /* True at return from initsecurity */
56 static uid_t real_uid = (uid_t) (-1);
57 static uid_t effective_uid = (uid_t) (-1);
58 static gid_t real_gid = (gid_t) (-1);
59 static gid_t effective_gid = (gid_t) (-1);
60
61 /*
62 * Run this at the beginning of the program to initialize this code and
63 * to drop privileges before someone uses them to shoot us in the foot.
64 * Do not pass(go), do not dollars += 200.
65 */
66 void
initsecurity()67 initsecurity()
68 {
69 int leffective_uid;
70
71 #ifdef HAVE_ALARM
72 alarm(0); /* can be inherited from parent process */
73 #endif
74 real_uid = getuid();
75 leffective_uid = geteuid();
76 if ((int) real_uid != leffective_uid && leffective_uid != 0) { /* sanity check */
77 errmsgno(EX_BAD,
78 _("Warning: setuid but not to root (uid=%ld, euid=%d)\n"),
79 (long) real_uid, leffective_uid);
80 fprintf(stderr, _("Dropping setuid privileges now.\n"));
81 neverneedroot();
82 } else {
83 effective_uid = leffective_uid;
84 }
85 real_gid = getgid();
86 effective_gid = getegid();
87 dontneedroot();
88 dontneedgroup();
89 }
90
91 /* Temporarily gain root privileges. */
92
93 #if defined _POSIX_SAVED_IDS && defined(HAVE_SETEUID) && defined SCO
94 /* SCO seems to lack the prototypes... */
95 int seteuid __PR((uid_t euid));
96 int setegid __PR((gid_t guid));
97 #endif
98
99 void
needroot(necessary)100 needroot(necessary)
101 int necessary;
102 {
103 #ifdef DEBUG
104 fprintf(stderr,
105 "call to needroot (_euid_=%d, uid=%d), current=%d/%d, pid=%d\n",
106 effective_uid, real_uid,
107 geteuid(), getuid(), getpid());
108 #endif
109 if (effective_uid) {
110 if (necessary) {
111 errmsgno(EX_BAD,
112 _("Fatal error: require root privilege but not setuid root.\n"));
113 exit(PERM_ERROR);
114 } else
115 return;
116 }
117 if (real_uid == (uid_t) (-1)) {
118 errmsgno(EX_BAD, _("Fatal error: initsecurity() not called.\n"));
119 exit(INTERNAL_ERROR);
120 }
121
122 if (geteuid() == 0)
123 return; /* nothing to do */
124
125 #if defined _POSIX_SAVED_IDS && defined(HAVE_SETEUID)
126 if (seteuid(effective_uid)) {
127 errmsg(_("Error with seteuid in needroot().\n"));
128 exit(PERM_ERROR);
129 }
130 #else
131 #if defined(HAVE_SETREUID)
132 if (setreuid(real_uid, effective_uid)) {
133 errmsg(_("Error with setreuid in needroot().\n"));
134 exit(PERM_ERROR);
135 }
136 #endif
137 #endif
138 if (geteuid() != 0 && necessary) {
139 errmsgno(EX_BAD, _("Fatal error: did not get root privilege.\n"));
140 exit(PERM_ERROR);
141 }
142 #ifdef DEBUG
143 fprintf(stderr,
144 "exit of needroot (_euid_=%d, uid=%d), current=%d/%d, pid=%d\n",
145 effective_uid, real_uid,
146 geteuid(), getuid(), getpid());
147 #endif
148 }
149
150 /*
151 * Temporarily drop root privileges.
152 */
153 void
dontneedroot()154 dontneedroot()
155 {
156 #ifdef DEBUG
157 fprintf(stderr,
158 "call to dontneedroot (_euid_=%d, uid=%d), current=%d/%d, pid=%d\n",
159 effective_uid, real_uid,
160 geteuid(), getuid(), getpid());
161 #endif
162 if (real_uid == (uid_t) (-1)) {
163 errmsgno(EX_BAD, _("Fatal error: initsecurity() not called.\n"));
164 exit(INTERNAL_ERROR);
165 }
166 if (effective_uid)
167 return;
168 if (geteuid() != 0)
169 return; /* nothing to do */
170
171 #if defined _POSIX_SAVED_IDS && defined(HAVE_SETEUID)
172 if (seteuid(real_uid)) {
173 errmsg(_("Error with seteuid in dontneedroot().\n"));
174 exit(PERM_ERROR);
175 }
176 #else
177 #if defined(HAVE_SETREUID)
178 if (setreuid(effective_uid, real_uid)) {
179 errmsg(_("Error with setreuid in dontneedroot().\n"));
180 exit(PERM_ERROR);
181 }
182 #endif
183 #endif
184 if (geteuid() != real_uid) {
185 errmsgno(EX_BAD,
186 _("Fatal error: did not drop root privilege.\n"));
187 #ifdef DEBUG
188 fprintf(stderr,
189 "in to dontneedroot (_euid_=%d, uid=%d), current=%d/%d, pid=%d\n",
190 effective_uid, real_uid,
191 geteuid(), getuid(), getpid());
192 #endif
193 exit(PERM_ERROR);
194 }
195 }
196
197 /*
198 * Permanently drop root privileges.
199 */
200 void
neverneedroot()201 neverneedroot()
202 {
203 #ifdef DEBUG
204 fprintf(stderr,
205 "call to neverneedroot (_euid_=%d, uid=%d), current=%d/%d, pid=%d\n",
206 effective_uid, real_uid,
207 geteuid(), getuid(), getpid());
208 #endif
209 if (real_uid == (uid_t) (-1)) {
210 errmsgno(EX_BAD, _("Fatal error: initsecurity() not called.\n"));
211 exit(INTERNAL_ERROR);
212 }
213 if (geteuid() != effective_uid) {
214 needroot(1);
215 }
216 if (geteuid() == effective_uid) {
217 #if defined(HAVE_SETUID)
218 if (setuid(real_uid)) {
219 errmsg(_("Error with setuid in neverneedroot().\n"));
220 exit(PERM_ERROR);
221 }
222 #endif
223 }
224 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \
225 defined(__DragonFly__) /* XXX this is a big hack and and not a permanent solution */
226 else {
227 #if defined(HAVE_SETUID)
228 if (setuid(real_uid)) {
229 errmsg(_("Error with setuid in neverneedroot().\n"));
230 exit(PERM_ERROR);
231 }
232 #endif
233 }
234 #endif
235 if (geteuid() != real_uid || getuid() != real_uid) {
236 errmsgno(EX_BAD,
237 _("Fatal error: did not drop root privilege.\n"));
238 #ifdef DEBUG
239 fprintf(stderr,
240 "in to neverneedroot (_euid_=%d, uid=%d), current=%d/%d, pid=%d\n",
241 effective_uid, real_uid,
242 geteuid(), getuid(), getpid());
243 #endif
244 exit(PERM_ERROR);
245 }
246 effective_uid = real_uid;
247 #ifdef DEBUG
248 fprintf(stderr,
249 "exit of neverneedroot (_euid_=%d, uid=%d), current=%d/%d, pid=%d\n",
250 effective_uid, real_uid,
251 geteuid(), getuid(), getpid());
252 #endif
253 }
254
255 /* Temporarily gain group privileges. */
256
257 void
needgroup(necessary)258 needgroup(necessary)
259 int necessary;
260 {
261 #ifdef DEBUG
262 fprintf(stderr,
263 "call to needgroup (egid=%d, gid=%d), current=%d/%d, pid=%d\n",
264 effective_gid, real_gid,
265 getegid(), getgid(), getpid());
266 #endif
267 if (real_gid == (gid_t) (-1)) {
268 errmsgno(EX_BAD,
269 _("Fatal error: initsecurity() not called.\n"));
270 exit(INTERNAL_ERROR);
271 }
272
273 if (getegid() == effective_gid)
274 return; /* nothing to do */
275
276 #if defined _POSIX_SAVED_IDS && defined(HAVE_SETEGID)
277 if (setegid(effective_gid)) {
278 errmsg(_("Error with setegid in needgroup().\n"));
279 exit(PERM_ERROR);
280 }
281 #else
282 #if defined(HAVE_SETREGID)
283 if (setregid(real_gid, effective_gid)) {
284 errmsg(_("Error with setregid in needgroup().\n"));
285 exit(PERM_ERROR);
286 }
287 #endif
288 #endif
289 if (necessary && getegid() != effective_gid) {
290 errmsgno(EX_BAD,
291 _("Fatal error: did not get group privilege.\n"));
292 exit(PERM_ERROR);
293 }
294 }
295
296 /*
297 * Temporarily drop group privileges.
298 */
299 void
dontneedgroup()300 dontneedgroup()
301 {
302 #ifdef DEBUG
303 fprintf(stderr,
304 "call to dontneedgroup (egid=%d, gid=%d), current=%d/%d, pid=%d\n",
305 effective_gid, real_gid,
306 getegid(), getgid(), getpid());
307 #endif
308 if (real_gid == (gid_t) (-1)) {
309 errmsgno(EX_BAD, _("Fatal error: initsecurity() not called.\n"));
310 exit(INTERNAL_ERROR);
311 }
312 if (getegid() != effective_gid)
313 return; /* nothing to do */
314 #if defined _POSIX_SAVED_IDS && defined(HAVE_SETEGID)
315 if (setegid(real_gid)) {
316 errmsg(_("Error with setegid in dontneedgroup().\n"));
317 exit(PERM_ERROR);
318 }
319 #else
320 #if defined(HAVE_SETREGID)
321 if (setregid(effective_gid, real_gid)) {
322 errmsg(_("Error with setregid in dontneedgroup().\n"));
323 exit(PERM_ERROR);
324 }
325 #endif
326 #endif
327 if (getegid() != real_gid) {
328 errmsgno(EX_BAD,
329 _("Fatal error: did not drop group privilege.\n"));
330 exit(PERM_ERROR);
331 }
332 #ifdef DEBUG
333 fprintf(stderr,
334 "exit if dontneedgroup (egid=%d, gid=%d), current=%d/%d, pid=%d\n",
335 effective_gid, real_gid,
336 getegid(), getgid(), getpid());
337 #endif
338 }
339
340 /*
341 * Permanently drop group privileges.
342 */
343 void
neverneedgroup()344 neverneedgroup()
345 {
346 #ifdef DEBUG
347 fprintf(stderr,
348 "call to neverneedgroup (egid=%d, gid=%d), current=%d/%d, pid=%d\n",
349 effective_gid, real_gid,
350 getegid(), getgid(), getpid());
351 #endif
352 if (real_gid == (gid_t) (-1)) {
353 errmsgno(EX_BAD, _("Fatal error: initsecurity() not called.\n"));
354 exit(INTERNAL_ERROR);
355 }
356 if (getegid() != effective_gid) {
357 needgroup(1);
358 }
359 if (getegid() == effective_gid) {
360 #if defined(HAVE_SETGID)
361 if (setgid(real_gid)) {
362 errmsg(_("Error with setgid in neverneedgroup().\n"));
363 exit(PERM_ERROR);
364 }
365 #endif
366 }
367 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \
368 defined(__DragonFly__) /* XXX this is a big hack and and not a permanent solution */
369 else {
370 #if defined(HAVE_SETGID)
371 if (setgid(real_gid)) {
372 errmsg(_("Error with setgid in neverneedgroup().\n"));
373 exit(PERM_ERROR);
374 }
375 #endif
376 }
377 #endif
378 if (getegid() != real_gid || getgid() != real_gid) {
379 errmsgno(EX_BAD,
380 _("Fatal error: did not drop group privilege.\n"));
381 #ifdef DEBUG
382 fprintf(stderr,
383 "in to neverneedgroup (_egid_=%d, gid=%d), current=%d/%d, pid=%d\n",
384 effective_gid, real_gid,
385 getegid(), getgid(), getpid());
386 #endif
387 exit(PERM_ERROR);
388 }
389 effective_gid = real_gid;
390 }
391
392 #if defined(HPUX)
393 int
seteuid(uid)394 seteuid(uid)
395 uid_t uid;
396 {
397 return (setresuid(-1, uid, -1));
398 }
399
400 int
setreuid(uid1,uid2)401 setreuid(uid1, uid2)
402 uid_t uid1;
403 uid_t uid2;
404 {
405 return (setresuid(uid2, uid2, uid1 == uid2 ? uid2 : 0));
406 }
407
408 int
setregid(gid1,gid2)409 setregid(gid1, gid2)
410 gid_t gid1;
411 gid_t gid2;
412 {
413 return (setresgid(gid2, gid2, gid1 == gid2 ? gid2 : 0));
414 }
415 #endif
416