1 /* setuid.c --- management of runtime privileges.
2 * xscreensaver, Copyright (c) 1993-1998, 2005 Jamie Zawinski <jwz@jwz.org>
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation. No representations are made about the suitability of this
9 * software for any purpose. It is provided "as is" without express or
17 #include <X11/Xlib.h> /* not used for much... */
19 /* This file doesn't need the Xt headers, so stub these types out... */
21 #define XtAppContext void*
22 #define XrmDatabase void*
23 #define XtIntervalId void*
24 #define XtPointer void*
27 #include "xscreensaver.h"
33 #include <pwd.h> /* for getpwnam() and struct passwd */
34 #include <grp.h> /* for getgrgid() and struct group */
37 uid_gid_string (uid_t uid, gid_t gid)
44 sprintf (buf, "%.100s/%.100s (%ld/%ld)",
45 (p && p->pw_name ? p->pw_name : "???"),
46 (g && g->gr_name ? g->gr_name : "???"),
47 (long) uid, (long) gid);
53 describe_uids (saver_info *si, FILE *out)
57 uid_t euid = geteuid();
58 gid_t egid = getegid();
59 char *s1 = strdup (uid_gid_string (uid, gid));
60 char *s2 = strdup (uid_gid_string (euid, egid));
62 if (si->orig_uid && *si->orig_uid &&
63 (!!strcmp (si->orig_uid, s1) ||
64 !!strcmp (si->orig_uid, s2)))
65 fprintf (out, "%s: initial effective uid/gid was %s\n", blurb(),
68 fprintf (out, "%s: running as %s", blurb(), s1);
69 if (uid != euid || gid != egid)
70 fprintf (out, "; effectively %s", s2);
78 set_ids_by_number (uid_t uid, gid_t gid, char **message_ret)
83 struct passwd *p = getpwuid (uid);
84 struct group *g = getgrgid (gid);
89 /* Rumor has it that some implementations of of setuid() do nothing
90 when called with -1; therefore, if the "nobody" user has a uid of
91 -1, then that would be Really Bad. Rumor further has it that such
92 systems really ought to be using -2 for "nobody", since that works.
93 So, if we get a uid (or gid, for good measure) of -1, switch to -2
94 instead. Note that this must be done after we've looked up the
95 user/group names with getpwuid(-1) and/or getgrgid(-1).
97 if (gid == (gid_t) -1) gid = (gid_t) -2;
98 if (uid == (uid_t) -1) uid = (uid_t) -2;
101 if (setgroups (1, &gid) < 0)
102 sgs_errno = errno ? errno : -1;
105 if (setgid (gid) != 0)
106 gid_errno = errno ? errno : -1;
109 if (setuid (uid) != 0)
110 uid_errno = errno ? errno : -1;
112 if (uid_errno == 0 && gid_errno == 0 && sgs_errno == 0)
114 static char buf [1024];
115 sprintf (buf, "changed uid/gid to %.100s/%.100s (%ld/%ld).",
116 (p && p->pw_name ? p->pw_name : "???"),
117 (g && g->gr_name ? g->gr_name : "???"),
118 (long) uid, (long) gid);
128 sprintf (buf, "%s: couldn't setgroups to %.100s (%ld)",
130 (g && g->gr_name ? g->gr_name : "???"),
133 fprintf(stderr, "%s: unknown error\n", buf);
143 sprintf (buf, "%s: couldn't set gid to %.100s (%ld)",
145 (g && g->gr_name ? g->gr_name : "???"),
148 fprintf(stderr, "%s: unknown error\n", buf);
158 sprintf (buf, "%s: couldn't set uid to %.100s (%ld)",
160 (p && p->pw_name ? p->pw_name : "???"),
163 fprintf(stderr, "%s: unknown error\n", buf);
176 /* If we've been run as setuid or setgid to someone else (most likely root)
177 turn off the extra permissions so that random user-specified programs
178 don't get special privileges. (On some systems it is necessary to install
179 this program as setuid root in order to read the passwd file to implement
182 *** WARNING: DO NOT DISABLE ANY OF THE FOLLOWING CODE!
183 If you do so, you will open a security hole. See the sections
184 of the xscreensaver manual titled "LOCKING AND ROOT LOGINS",
188 hack_uid (saver_info *si)
191 /* Discard privileges, and set the effective user/group ids to the
192 real user/group ids. That is, give up our "chmod +s" rights.
195 uid_t euid = geteuid();
196 gid_t egid = getegid();
197 uid_t uid = getuid();
198 gid_t gid = getgid();
200 si->orig_uid = strdup (uid_gid_string (euid, egid));
202 if (uid != euid || gid != egid)
203 if (set_ids_by_number (uid, gid, &si->uid_message) != 0)
204 saver_exit (si, 1, 0);
208 /* Locking can't work when running as root, because we have no way of
209 knowing what the user id of the logged in user is (so we don't know
210 whose password to prompt for.)
212 *** WARNING: DO NOT DISABLE THIS CODE!
213 If you do so, you will open a security hole. See the sections
214 of the xscreensaver manual titled "LOCKING AND ROOT LOGINS",
217 if (getuid() == (uid_t) 0)
219 si->locking_disabled_p = True;
220 si->nolock_reason = "running as root";
224 /* If we're running as root, switch to a safer user. This is above and
225 beyond the fact that we've disabling locking, above -- the theory is
226 that running graphics demos as root is just always a stupid thing
227 to do, since they have probably never been security reviewed and are
228 more likely to be buggy than just about any other kind of program.
229 (And that assumes non-malicious code. There are also attacks here.)
231 *** WARNING: DO NOT DISABLE THIS CODE!
232 If you do so, you will open a security hole. See the sections
233 of the xscreensaver manual titled "LOCKING AND ROOT LOGINS",
236 if (getuid() == (uid_t) 0)
240 p = getpwnam ("nobody");
241 if (! p) p = getpwnam ("noaccess");
242 if (! p) p = getpwnam ("daemon");
246 "%s: running as root, and couldn't find a safer uid.\n",
248 saver_exit(si, 1, 0);
251 if (set_ids_by_number (p->pw_uid, p->pw_gid, &si->uid_message) != 0)
252 saver_exit (si, -1, 0);
256 /* If there's anything even remotely funny looking about the passwd struct,
257 or if we're running as some other user from the list below (a
258 non-comprehensive selection of users known to be privileged in some way,
259 and not normal end-users) then disable locking. If it was possible,
260 switching to "nobody" would be the thing to do, but only root itself has
261 the privs to do that.
263 *** WARNING: DO NOT DISABLE THIS CODE!
264 If you do so, you will open a security hole. See the sections
265 of the xscreensaver manual titled "LOCKING AND ROOT LOGINS",
269 uid_t uid = getuid (); /* get it again */
270 struct passwd *p = getpwuid (uid); /* get it again */
276 p->pw_uid == (uid_t) 0 ||
277 p->pw_uid == (uid_t) -1 ||
278 p->pw_uid == (uid_t) -2 ||
281 !strcmp (p->pw_name, "root") ||
282 !strcmp (p->pw_name, "nobody") ||
283 !strcmp (p->pw_name, "noaccess") ||
284 !strcmp (p->pw_name, "operator") ||
285 !strcmp (p->pw_name, "daemon") ||
286 !strcmp (p->pw_name, "bin") ||
287 !strcmp (p->pw_name, "adm") ||
288 !strcmp (p->pw_name, "sys") ||
289 !strcmp (p->pw_name, "games"))
291 static char buf [1024];
292 sprintf (buf, "running as %.100s",
293 (p && p->pw_name && *p->pw_name
294 ? p->pw_name : "<unknown>"));
295 si->nolock_reason = buf;
296 si->locking_disabled_p = True;
297 si->dangerous_uid_p = True;