1 /* setuid.c --- management of runtime privileges.
2 * xscreensaver, Copyright (c) 1993-1998 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 #ifndef NO_SETUID /* whole file */
19 #include <X11/Xlib.h> /* not used for much... */
21 /* This file doesn't need the Xt headers, so stub these types out... */
23 #define XtAppContext void*
24 #define XrmDatabase void*
25 #define XtIntervalId void*
26 #define XtPointer void*
29 #include "xscreensaver.h"
35 #include <pwd.h> /* for getpwnam() and struct passwd */
36 #include <grp.h> /* for getgrgid() and struct group */
40 uid_gid_string (uid_t uid, gid_t gid)
47 sprintf (buf, "%s/%s (%ld/%ld)",
48 (p && p->pw_name ? p->pw_name : "???"),
49 (g && g->gr_name ? g->gr_name : "???"),
50 (long) uid, (long) gid);
56 describe_uids (saver_info *si, FILE *out)
60 uid_t euid = geteuid();
61 gid_t egid = getegid();
62 char *s1 = strdup (uid_gid_string (uid, gid));
63 char *s2 = strdup (uid_gid_string (euid, egid));
65 if (si->orig_uid && *si->orig_uid &&
66 (!!strcmp (si->orig_uid, s1) ||
67 !!strcmp (si->orig_uid, s2)))
68 fprintf (out, "%s: initial effective uid/gid was %s\n", blurb(),
71 fprintf (out, "%s: running as %s", blurb(), s1);
72 if (uid != euid || gid != egid)
73 fprintf (out, "; effectively %s", s2);
81 set_ids_by_name (struct passwd *p, struct group *g, char **message_ret)
85 uid_t uid = p->pw_uid;
86 gid_t gid = g->gr_gid;
91 /* Rumor has it that some implementations of of setuid() do nothing
92 when called with -1; therefore, if the "nobody" user has a uid of
93 -1, then that would be Really Bad. Rumor further has it that such
94 systems really ought to be using -2 for "nobody", since that works.
95 So, if we get a uid (or gid, for good measure) of -1, switch to -2
98 if (gid == (gid_t) -1) gid = (gid_t) -2;
99 if (uid == (uid_t) -1) uid = (uid_t) -2;
102 if (setgid (gid) != 0)
103 gid_errno = errno ? errno : -1;
106 if (setuid (uid) != 0)
107 uid_errno = errno ? errno : -1;
109 if (uid_errno == 0 && gid_errno == 0)
111 static char buf [1024];
112 sprintf (buf, "changed uid/gid to %s/%s (%ld/%ld).",
113 p->pw_name, (g ? g->gr_name : "???"),
114 (long) uid, (long) gid);
124 sprintf (buf, "%s: couldn't set gid to %s (%ld)",
126 (g ? g->gr_name : "???"),
129 fprintf(stderr, "%s: unknown error\n", buf);
136 sprintf (buf, "%s: couldn't set uid to %s (%ld)",
138 (p ? p->pw_name : "???"),
141 fprintf(stderr, "%s: unknown error\n", buf);
151 set_ids_by_number (uid_t uid, gid_t gid, char **message_ret)
161 sprintf (buf, "%s: error looking up name of user %d", blurb(),
166 fprintf (stderr, "%s: unknown error.\n", buf);
175 sprintf (buf, "%s: error looking up name of group %d", blurb(),
180 fprintf (stderr, "%s: unknown error.\n", buf);
184 return set_ids_by_name (p, g, message_ret);
188 /* If we've been run as setuid or setgid to someone else (most likely root)
189 turn off the extra permissions so that random user-specified programs
190 don't get special privileges. (On some systems it is necessary to install
191 this program as setuid root in order to read the passwd file to implement
194 *** WARNING: DO NOT DISABLE ANY OF THE FOLLOWING CODE!
195 If you do so, you will open a security hole. See the sections
196 of the xscreensaver manual titled "LOCKING AND ROOT LOGINS",
200 hack_uid (saver_info *si)
203 /* Discard privileges, and set the effective user/group ids to the
204 real user/group ids. That is, give up our "chmod +s" rights.
207 uid_t euid = geteuid();
208 gid_t egid = getegid();
209 uid_t uid = getuid();
210 gid_t gid = getgid();
212 si->orig_uid = strdup (uid_gid_string (euid, egid));
214 if (uid != euid || gid != egid)
215 if (set_ids_by_number (uid, gid, &si->uid_message) != 0)
216 saver_exit (si, 1, 0);
220 /* Locking can't work when running as root, because we have no way of
221 knowing what the user id of the logged in user is (so we don't know
222 whose password to prompt for.)
224 *** WARNING: DO NOT DISABLE THIS CODE!
225 If you do so, you will open a security hole. See the sections
226 of the xscreensaver manual titled "LOCKING AND ROOT LOGINS",
229 if (getuid() == (uid_t) 0)
231 si->locking_disabled_p = True;
232 si->nolock_reason = "running as root";
236 /* If we're running as root, switch to a safer user. This is above and
237 beyond the fact that we've disabling locking, above -- the theory is
238 that running graphics demos as root is just always a stupid thing
239 to do, since they have probably never been security reviewed and are
240 more likely to be buggy than just about any other kind of program.
241 (And that assumes non-malicious code. There are also attacks here.)
243 *** WARNING: DO NOT DISABLE THIS CODE!
244 If you do so, you will open a security hole. See the sections
245 of the xscreensaver manual titled "LOCKING AND ROOT LOGINS",
248 if (getuid() == (uid_t) 0)
252 p = getpwnam ("nobody");
253 if (! p) p = getpwnam ("noaccess");
254 if (! p) p = getpwnam ("daemon");
258 "%s: running as root, and couldn't find a safer uid.\n",
260 saver_exit(si, 1, 0);
263 if (set_ids_by_number (p->pw_uid, p->pw_gid, &si->uid_message) != 0)
264 saver_exit (si, -1, 0);
268 /* If there's anything even remotely funny looking about the passwd struct,
269 or if we're running as some other user from the list below (a
270 non-comprehensive selection of users known to be privileged in some way,
271 and not normal end-users) then disable locking. If it was possible,
272 switching to "nobody" would be the thing to do, but only root itself has
273 the privs to do that.
275 *** WARNING: DO NOT DISABLE THIS CODE!
276 If you do so, you will open a security hole. See the sections
277 of the xscreensaver manual titled "LOCKING AND ROOT LOGINS",
281 uid_t uid = getuid (); /* get it again */
282 struct passwd *p = getpwuid (uid); /* get it again */
288 p->pw_uid == (uid_t) 0 ||
289 p->pw_uid == (uid_t) -1 ||
290 p->pw_uid == (uid_t) -2 ||
293 !strcmp (p->pw_name, "root") ||
294 !strcmp (p->pw_name, "nobody") ||
295 !strcmp (p->pw_name, "noaccess") ||
296 !strcmp (p->pw_name, "operator") ||
297 !strcmp (p->pw_name, "daemon") ||
298 !strcmp (p->pw_name, "bin") ||
299 !strcmp (p->pw_name, "adm") ||
300 !strcmp (p->pw_name, "sys") ||
301 !strcmp (p->pw_name, "games"))
303 static char buf [1024];
304 sprintf (buf, "running as %s",
305 (p && p->pw_name && *p->pw_name
306 ? p->pw_name : "<unknown>"));
307 si->nolock_reason = buf;
308 si->locking_disabled_p = True;
309 si->dangerous_uid_p = True;
314 #else /* !NO_SETUID */
316 void hack_uid (saver_info *si) { }
317 void describe_uids (saver_info *si, FILE *out) { }
319 #endif /* NO_SETUID */