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 #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, "%s/%s (%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)
82 struct passwd *p = getpwuid (uid);
83 struct group *g = getgrgid (gid);
88 /* Rumor has it that some implementations of of setuid() do nothing
89 when called with -1; therefore, if the "nobody" user has a uid of
90 -1, then that would be Really Bad. Rumor further has it that such
91 systems really ought to be using -2 for "nobody", since that works.
92 So, if we get a uid (or gid, for good measure) of -1, switch to -2
93 instead. Note that this must be done after we've looked up the
94 user/group names with getpwuid(-1) and/or getgrgid(-1).
96 if (gid == (gid_t) -1) gid = (gid_t) -2;
97 if (uid == (uid_t) -1) uid = (uid_t) -2;
100 if (setgid (gid) != 0)
101 gid_errno = errno ? errno : -1;
104 if (setuid (uid) != 0)
105 uid_errno = errno ? errno : -1;
107 if (uid_errno == 0 && gid_errno == 0)
109 static char buf [1024];
110 sprintf (buf, "changed uid/gid to %s/%s (%ld/%ld).",
111 (p && p->pw_name ? p->pw_name : "???"),
112 (g && g->gr_name ? g->gr_name : "???"),
113 (long) uid, (long) gid);
123 sprintf (buf, "%s: couldn't set gid to %s (%ld)",
125 (g && g->gr_name ? g->gr_name : "???"),
128 fprintf(stderr, "%s: unknown error\n", buf);
135 sprintf (buf, "%s: couldn't set uid to %s (%ld)",
137 (p && p->pw_name ? p->pw_name : "???"),
140 fprintf(stderr, "%s: unknown error\n", buf);
150 /* If we've been run as setuid or setgid to someone else (most likely root)
151 turn off the extra permissions so that random user-specified programs
152 don't get special privileges. (On some systems it is necessary to install
153 this program as setuid root in order to read the passwd file to implement
156 *** WARNING: DO NOT DISABLE ANY OF THE FOLLOWING CODE!
157 If you do so, you will open a security hole. See the sections
158 of the xscreensaver manual titled "LOCKING AND ROOT LOGINS",
162 hack_uid (saver_info *si)
165 /* Discard privileges, and set the effective user/group ids to the
166 real user/group ids. That is, give up our "chmod +s" rights.
169 uid_t euid = geteuid();
170 gid_t egid = getegid();
171 uid_t uid = getuid();
172 gid_t gid = getgid();
174 si->orig_uid = strdup (uid_gid_string (euid, egid));
176 if (uid != euid || gid != egid)
177 if (set_ids_by_number (uid, gid, &si->uid_message) != 0)
178 saver_exit (si, 1, 0);
182 /* Locking can't work when running as root, because we have no way of
183 knowing what the user id of the logged in user is (so we don't know
184 whose password to prompt for.)
186 *** WARNING: DO NOT DISABLE THIS CODE!
187 If you do so, you will open a security hole. See the sections
188 of the xscreensaver manual titled "LOCKING AND ROOT LOGINS",
191 if (getuid() == (uid_t) 0)
193 si->locking_disabled_p = True;
194 si->nolock_reason = "running as root";
198 /* If we're running as root, switch to a safer user. This is above and
199 beyond the fact that we've disabling locking, above -- the theory is
200 that running graphics demos as root is just always a stupid thing
201 to do, since they have probably never been security reviewed and are
202 more likely to be buggy than just about any other kind of program.
203 (And that assumes non-malicious code. There are also attacks here.)
205 *** WARNING: DO NOT DISABLE THIS CODE!
206 If you do so, you will open a security hole. See the sections
207 of the xscreensaver manual titled "LOCKING AND ROOT LOGINS",
210 if (getuid() == (uid_t) 0)
214 p = getpwnam ("nobody");
215 if (! p) p = getpwnam ("noaccess");
216 if (! p) p = getpwnam ("daemon");
220 "%s: running as root, and couldn't find a safer uid.\n",
222 saver_exit(si, 1, 0);
225 if (set_ids_by_number (p->pw_uid, p->pw_gid, &si->uid_message) != 0)
226 saver_exit (si, -1, 0);
230 /* If there's anything even remotely funny looking about the passwd struct,
231 or if we're running as some other user from the list below (a
232 non-comprehensive selection of users known to be privileged in some way,
233 and not normal end-users) then disable locking. If it was possible,
234 switching to "nobody" would be the thing to do, but only root itself has
235 the privs to do that.
237 *** WARNING: DO NOT DISABLE THIS CODE!
238 If you do so, you will open a security hole. See the sections
239 of the xscreensaver manual titled "LOCKING AND ROOT LOGINS",
243 uid_t uid = getuid (); /* get it again */
244 struct passwd *p = getpwuid (uid); /* get it again */
250 p->pw_uid == (uid_t) 0 ||
251 p->pw_uid == (uid_t) -1 ||
252 p->pw_uid == (uid_t) -2 ||
255 !strcmp (p->pw_name, "root") ||
256 !strcmp (p->pw_name, "nobody") ||
257 !strcmp (p->pw_name, "noaccess") ||
258 !strcmp (p->pw_name, "operator") ||
259 !strcmp (p->pw_name, "daemon") ||
260 !strcmp (p->pw_name, "bin") ||
261 !strcmp (p->pw_name, "adm") ||
262 !strcmp (p->pw_name, "sys") ||
263 !strcmp (p->pw_name, "games"))
265 static char buf [1024];
266 sprintf (buf, "running as %s",
267 (p && p->pw_name && *p->pw_name
268 ? p->pw_name : "<unknown>"));
269 si->nolock_reason = buf;
270 si->locking_disabled_p = True;
271 si->dangerous_uid_p = True;