http://ftp.aanet.ru/pub/Linux/X11/apps/xscreensaver-2.31.tar.gz
[xscreensaver] / driver / setuid.c
diff --git a/driver/setuid.c b/driver/setuid.c
new file mode 100644 (file)
index 0000000..87bb4c3
--- /dev/null
@@ -0,0 +1,215 @@
+/* setuid.c --- management of runtime priveleges.
+ * xscreensaver, Copyright (c) 1993-1998 Jamie Zawinski <jwz@jwz.org>
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation.  No representations are made about the suitability of this
+ * software for any purpose.  It is provided "as is" without express or 
+ * implied warranty.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifndef NO_SETUID /* whole file */
+
+#include <X11/Xlib.h>          /* not used for much... */
+
+/* This file doesn't need the Xt headers, so stub these types out... */
+#undef XtPointer
+#define XtAppContext void*
+#define XrmDatabase  void*
+#define XtIntervalId void*
+#define XtPointer    void*
+#define Widget       void*
+
+#include "xscreensaver.h"
+
+#ifndef EPERM
+#include <errno.h>
+#endif
+
+#include <pwd.h>               /* for getpwnam() and struct passwd */
+#include <grp.h>               /* for getgrgid() and struct group */
+
+
+static const char *
+uid_gid_string(uid_t uid, gid_t gid)
+{
+  static char buf[255];
+  struct passwd *p = 0;
+  struct group *g = 0;
+  p = getpwuid (uid);
+  g = getgrgid (gid);
+  sprintf (buf, "%s/%s (%ld/%ld)",
+          (p && p->pw_name ? p->pw_name : "???"),
+          (g && g->gr_name ? g->gr_name : "???"),
+          (long) uid, (long) gid);
+  return buf;
+}
+
+
+void
+describe_uids (saver_info *si, FILE *out)
+{
+  uid_t uid = getuid();
+  gid_t gid = getgid();
+  uid_t euid = geteuid();
+  gid_t egid = getegid();
+  char *s1 = strdup (uid_gid_string (uid, gid));
+  char *s2 = strdup (uid_gid_string (euid, egid));
+
+  if (si->orig_uid && *si->orig_uid)
+    fprintf (out, "%s: initial effective uid/gid was %s\n", blurb(),
+            si->orig_uid);
+  fprintf (out, "%s: running as %s", blurb(), s1);
+  if (uid != euid || gid != egid)
+    fprintf (out, "; effectively %s", s2);
+  fprintf(out, "\n");
+  free(s1);
+  free(s2);
+}
+
+
+/* If we've been run as setuid or setgid to someone else (most likely root)
+   turn off the extra permissions so that random user-specified programs
+   don't get special privileges.  (On some systems it is necessary to install
+   this program as setuid root in order to read the passwd file to implement
+   lock-mode.)
+ */
+void
+hack_uid (saver_info *si)
+{
+  si->orig_uid = strdup (uid_gid_string (geteuid(), getegid()));
+
+  setgid (getgid ());
+  setuid (getuid ());
+
+  /* If we're being run as root (as from xdm) then switch the user id
+     to something safe. */
+  if (getuid () == 0)
+    {
+      struct passwd *p = 0;
+      struct group *g = 0;
+      int uid_errno = 0;
+      int gid_errno = 0;
+
+      /* Locking can't work when running as root, because we have no way of
+        knowing what the user id of the logged in user is (so we don't know
+        whose password to prompt for.)
+       */
+      si->locking_disabled_p = True;
+      si->nolock_reason = "running as root";
+      p = getpwnam ("nobody");
+      if (! p) p = getpwnam ("noaccess");
+      if (! p) p = getpwnam ("daemon");
+      if (! p)
+       {
+         fprintf (stderr,
+                  "%s: running as root, and couldn't find a safer uid.\n",
+                  blurb());
+         saver_exit(si, 1, 0);
+       }
+
+      g = getgrgid (p->pw_gid);
+
+      /* Rumor has it that some implementations of of setuid() do nothing
+        when called with -1; therefore, if the "nobody" user has a uid of
+        -1, then that would be Really Bad.  Rumor further has it that such
+        systems really ought to be using -2 for "nobody", since that works.
+        So, if we get a uid (or gid, for good measure) of -1, switch to -2
+        instead.
+       */
+
+      if (p->pw_gid == -1) p->pw_gid = -2;
+      if (p->pw_uid == -1) p->pw_uid = -2;
+
+
+      /* Change the gid to be a safe one, then change the uid to be a safe
+        one (must do it in this order, because root privs vanish when uid
+        is changed, and after that, gid can't be changed.)
+       */
+      if (setgid (p->pw_gid) != 0)
+       gid_errno = errno ? errno : -1;
+      if (setuid (p->pw_uid) != 0)
+       uid_errno = errno ? errno : -1;
+
+      if (uid_errno == 0 && gid_errno == 0)
+       {
+         static char buf [1024];
+         sprintf (buf, "changed uid/gid to %s/%s (%ld/%ld).",
+                  p->pw_name, (g ? g->gr_name : "???"),
+                  (long) p->pw_uid, (long) p->pw_gid);
+         si->uid_message = buf;
+       }
+      else
+       {
+         char buf [1024];
+         if (gid_errno)
+           {
+             sprintf (buf, "%s: couldn't set gid to %s (%ld)",
+                      blurb(),
+                      (g ? g->gr_name : "???"),
+                      (long) p->pw_gid);
+             if (gid_errno == -1)
+               fprintf(stderr, "%s: unknown error\n", buf);
+             else
+               perror(buf);
+           }
+
+         if (uid_errno)
+           {
+             sprintf (buf, "%s: couldn't set uid to %s (%ld)",
+                      blurb(),
+                      (p ? p->pw_name : "???"),
+                      (long) p->pw_uid);
+             if (uid_errno == -1)
+               fprintf(stderr, "%s: unknown error\n", buf);
+             else
+               perror(buf);
+           }
+       }
+
+      if (uid_errno != 0)
+       {
+         /* We'd better exit rather than continue running as root.
+            But if we switched uid but not gid, continue running,
+            since that doesn't really matter.  (Right?)
+          */
+         saver_exit (si, -1, 0);
+       }
+    }
+# ifndef NO_LOCKING
+ else  /* disable locking if already being run as "someone else" */
+   {
+     struct passwd *p = getpwuid (getuid ());
+     if (!p ||
+        !strcmp (p->pw_name, "root") ||
+        !strcmp (p->pw_name, "nobody") ||
+        !strcmp (p->pw_name, "noaccess") ||
+        !strcmp (p->pw_name, "operator") ||
+        !strcmp (p->pw_name, "daemon") ||
+        !strcmp (p->pw_name, "bin") ||
+        !strcmp (p->pw_name, "adm") ||
+        !strcmp (p->pw_name, "sys") ||
+        !strcmp (p->pw_name, "games"))
+       {
+        static char buf [1024];
+        sprintf (buf, "running as %s", p->pw_name);
+        si->nolock_reason = buf;
+        si->locking_disabled_p = True;
+       }
+   }
+# endif /* !NO_LOCKING */
+}
+
+#else  /* !NO_SETUID */
+
+void hack_uid (saver_info *si) { }
+void hack_uid_warn (saver_info *si) { }
+void describe_uids (saver_info *si) { }
+
+#endif /* NO_SETUID */