2 * This file has been modified for the cdrkit suite.
4 * The behaviour and appearence of the program code below can differ to a major
5 * extent from the version distributed by the original author(s).
7 * For details, see Changelog file distributed with the cdrkit package. If you
8 * received this file from another source then ask the distributing person for
9 * a log of modifications.
13 /* @(#)setuid.c 1.11 06/02/19 Copyright 1998,1999,2004 Heiko Eissfeldt, Copyright 2004-2006 J. Schilling */
14 /* Security functions by zblaxell
16 If these functions fail, it is because there was an installation error
17 or a programming error, and we can't be sure about what privileges
18 we do or do not have. This means we might not be able to recover
19 the privileges we need to fix anything that may be broken (e.g. the
20 CDDA state of some interface types), and we may in fact do something
21 quite dangerous (like write to the WAV file as root).
23 In any case, it is unsafe to do anything but exit *now*. Ideally we'd
24 kill -9 our process group too, just to be sure. Root privileges are not
25 something you want floating around at random in user-level applications.
27 If any signal handlers or child processes are introduced into this
28 program, it will be necessary to call dontneedroot() or neverneedroot()
29 on entry, respectively; otherwise, it will be possible to trick
30 the program into executing the signal handler or child process with
31 root privileges by sending signals at the right time.
39 #include "exitcodes.h"
45 /* True at return from initsecurity */
46 static uid_t real_uid = (uid_t) (-1);
47 static uid_t effective_uid = (uid_t) (-1);
48 static gid_t real_gid = (gid_t) (-1);
49 static gid_t effective_gid = (gid_t) (-1);
51 /* Run this at the beginning of the program to initialize this code and
52 to drop privileges before someone uses them to shoot us in the foot.
53 Do not pass(go), do not dollars += 200. */
59 alarm(0); /* can be inherited from parent process */
61 leffective_uid = geteuid();
62 if ((int) real_uid != leffective_uid && leffective_uid != 0) { /* sanity check */
63 fprintf(stderr, "Warning: setuid but not to root (uid=%ld, euid=%d)\n", (long) real_uid, leffective_uid);
64 fprintf(stderr, "Dropping setuid privileges now.\n");
67 effective_uid = leffective_uid;
70 effective_gid = getegid();
75 /* Temporarily gain root privileges. */
77 #if defined _POSIX_SAVED_IDS && defined (HAVE_SETEUID) && defined SCO
78 /* SCO seems to lack the prototypes... */
79 int seteuid(uid_t euid);
80 int setegid(gid_t guid);
83 void needroot(int necessary)
86 fprintf(stderr, "call to needroot (_euid_=%d, uid=%d), current=%d/%d, pid=%d\n",
87 effective_uid, real_uid, geteuid(), getuid(), getpid());
91 fprintf(stderr, "Fatal error: require root privilege but not setuid root.\n");
96 if (real_uid == (uid_t) (-1)) {
97 fprintf(stderr, "Fatal error: initsecurity() not called.\n");
101 if (geteuid() == 0) return; /* nothing to do */
103 #if defined _POSIX_SAVED_IDS && defined (HAVE_SETEUID)
104 if (seteuid(effective_uid)) {
105 perror("seteuid in needroot()");
109 #if defined (HAVE_SETREUID)
110 if (setreuid(real_uid, effective_uid)) {
111 perror("setreuid in needroot()");
116 if (geteuid() != 0 && necessary) {
117 fprintf(stderr, "Fatal error: did not get root privilege.\n");
121 fprintf(stderr, "exit of needroot (_euid_=%d, uid=%d), current=%d/%d, pid=%d\n",
122 effective_uid, real_uid, geteuid(), getuid(), getpid());
126 /* Temporarily drop root privileges. */
131 fprintf(stderr, "call to dontneedroot (_euid_=%d, uid=%d), current=%d/%d, pid=%d\n",
132 effective_uid, real_uid, geteuid(), getuid(), getpid());
134 if (real_uid == (uid_t) (-1)) {
135 fprintf(stderr, "Fatal error: initsecurity() not called.\n");
136 exit(INTERNAL_ERROR);
140 if (geteuid() != 0) return; /* nothing to do */
142 #if defined _POSIX_SAVED_IDS && defined (HAVE_SETEUID)
143 if (seteuid(real_uid)) {
144 perror("seteuid in dontneedroot()");
148 #if defined (HAVE_SETREUID)
149 if (setreuid(effective_uid, real_uid)) {
150 perror("setreuid in dontneedroot()");
155 if (geteuid() != real_uid) {
156 fprintf(stderr, "Fatal error: did not drop root privilege.\n");
158 fprintf(stderr, "in to dontneedroot (_euid_=%d, uid=%d), current=%d/%d, pid=%d\n",
159 effective_uid, real_uid, geteuid(), getuid(), getpid());
165 /* Permanently drop root privileges. */
170 fprintf(stderr, "call to neverneedroot (_euid_=%d, uid=%d), current=%d/%d, pid=%d\n",
171 effective_uid, real_uid, geteuid(), getuid(), getpid());
173 if (real_uid == (uid_t) (-1)) {
174 fprintf(stderr, "Fatal error: initsecurity() not called.\n");
175 exit(INTERNAL_ERROR);
177 if (geteuid() == effective_uid) {
178 #if defined (HAVE_SETUID)
179 if (setuid(real_uid)) {
180 perror("setuid in neverneedroot()");
185 #if defined(__FreeBSD__) || defined(__DragonFly__) /* XXX this is a big hack and and not a permanent solution */
187 #if defined (HAVE_SETUID)
188 if (setuid(real_uid)) {
189 perror("setuid in neverneedroot()");
195 if (geteuid() != real_uid || getuid() != real_uid) {
196 fprintf(stderr, "Fatal error: did not drop root privilege.\n");
198 fprintf(stderr, "in to neverneedroot (_euid_=%d, uid=%d), current=%d/%d, pid=%d\n",
199 effective_uid, real_uid, geteuid(), getuid(), getpid());
203 effective_uid = real_uid;
205 fprintf(stderr, "exit of neverneedroot (_euid_=%d, uid=%d), current=%d/%d, pid=%d\n",
206 effective_uid, real_uid, geteuid(), getuid(), getpid());
210 /* Temporarily gain group privileges. */
212 void needgroup(int necessary)
215 fprintf(stderr, "call to needgroup (egid=%d, gid=%d), current=%d/%d, pid=%d\n",
216 effective_gid, real_gid, getegid(), getgid(), getpid());
218 if (real_gid == (gid_t) (-1)) {
219 fprintf(stderr, "Fatal error: initsecurity() not called.\n");
220 exit(INTERNAL_ERROR);
223 if (getegid() == effective_gid) return; /* nothing to do */
225 #if defined _POSIX_SAVED_IDS && defined (HAVE_SETEGID)
226 if (setegid(effective_gid)) {
227 perror("setegid in needgroup()");
231 #if defined (HAVE_SETREGID)
232 if (setregid(real_gid, effective_gid)) {
233 perror("setregid in needgroup()");
238 if (necessary && getegid() != effective_gid) {
239 fprintf(stderr, "Fatal error: did not get group privilege.\n");
244 /* Temporarily drop group privileges. */
249 fprintf(stderr, "call to dontneedgroup (egid=%d, gid=%d), current=%d/%d, pid=%d\n",
250 effective_gid, real_gid, getegid(), getgid(), getpid());
252 if (real_gid == (gid_t) (-1)) {
253 fprintf(stderr, "Fatal error: initsecurity() not called.\n");
254 exit(INTERNAL_ERROR);
256 if (getegid() != effective_gid) return; /* nothing to do */
257 #if defined _POSIX_SAVED_IDS && defined (HAVE_SETEGID)
258 if (setegid(real_gid)) {
259 perror("setegid in dontneedgroup()");
263 #if defined (HAVE_SETREGID)
264 if (setregid(effective_gid, real_gid)) {
265 perror("setregid in dontneedgroup()");
270 if (getegid() != real_gid) {
271 fprintf(stderr, "Fatal error: did not drop group privilege.\n");
275 fprintf(stderr, "exit if dontneedgroup (egid=%d, gid=%d), current=%d/%d, pid=%d\n",
276 effective_gid, real_gid, getegid(), getgid(), getpid());
280 /* Permanently drop group privileges. */
282 void neverneedgroup()
285 fprintf(stderr, "call to neverneedgroup (egid=%d, gid=%d), current=%d/%d, pid=%d\n",
286 effective_gid, real_gid, getegid(), getgid(), getpid());
288 if (real_gid == (gid_t) (-1)) {
289 fprintf(stderr, "Fatal error: initsecurity() not called.\n");
290 exit(INTERNAL_ERROR);
292 if (getegid() == effective_gid) {
293 #if defined (HAVE_SETGID)
294 if (setgid(real_gid)) {
295 perror("setgid in neverneedgroup()");
300 #if defined(__FreeBSD__) || defined(__DragonFly__) /* XXX this is a big hack and and not a permanent solution */
302 #if defined (HAVE_SETGID)
303 if (setgid(real_gid)) {
304 perror("setgid in neverneedgroup()");
310 if (getegid() != real_gid || getgid() != real_gid) {
311 fprintf(stderr, "Fatal error: did not drop group privilege.\n");
314 effective_gid = real_gid;
318 int seteuid(uid_t uid)
320 return setresuid(-1, uid, -1);
323 int setreuid(uid_t uid1, uid_t uid2)
325 return setresuid(uid2, uid2, uid1 == uid2 ? uid2 : 0);
328 int setregid(gid_t gid1, gid_t gid2)
330 return setresgid(gid2, gid2, gid1 == gid2 ? gid2 : 0);