cvsdist 5adf0d
--- coreutils-5.2.0/src/Makefile.am.pam	2004-02-23 17:40:54.000000000 +0000
cvsdist 5adf0d
+++ coreutils-5.2.0/src/Makefile.am	2004-02-23 17:40:54.000000000 +0000
cvsdist 5adf0d
@@ -66,7 +66,7 @@
cvsdist 5adf0d
 
cvsdist 5adf0d
 uptime_LDADD = $(LDADD) $(GETLOADAVG_LIBS)
cvsdist 5adf0d
 
cvsdist 5adf0d
-su_LDADD = $(LDADD) $(LIB_CRYPT)
cvsdist 5adf0d
+su_LDADD = $(LDADD) $(LIB_CRYPT) @LIB_PAM@
cvsdist 5adf0d
 
cvsdist 5adf0d
 $(PROGRAMS): ../lib/libfetish.a
cvsdist 5adf0d
 
cvsdist 5adf0d
--- coreutils-5.2.0/src/su.c.pam	2004-02-23 17:40:54.000000000 +0000
cvsdist 5adf0d
+++ coreutils-5.2.0/src/su.c	2004-02-23 17:40:54.000000000 +0000
cvsdist 5adf0d
@@ -38,6 +38,16 @@
cvsdist 5adf0d
    restricts who can su to UID 0 accounts.  RMS considers that to
cvsdist 5adf0d
    be fascist.
cvsdist 5adf0d
 
cvsdist 5adf0d
+#ifdef USE_PAM
cvsdist 5adf0d
+
cvsdist 5adf0d
+   Actually, with PAM, su has nothing to do with whether or not a
cvsdist 5adf0d
+   wheel group is enforced by su.  RMS tries to restrict your access
cvsdist 5adf0d
+   to a su which implements the wheel group, but PAM considers that
cvsdist 5adf0d
+   to be fascist, and gives the user/sysadmin the opportunity to
cvsdist 5adf0d
+   enforce a wheel group by proper editing of /etc/pam.conf
cvsdist 5adf0d
+
cvsdist 5adf0d
+#endif
cvsdist 5adf0d
+
cvsdist 5adf0d
    Options:
cvsdist 5adf0d
    -, -l, --login	Make the subshell a login shell.
cvsdist 5adf0d
 			Unset all environment variables except
cvsdist 5adf0d
@@ -81,6 +91,14 @@
cvsdist 5adf0d
    prototype (returning `int') in <unistd.h>.  */
cvsdist 5adf0d
 #define getusershell _getusershell_sys_proto_
cvsdist 5adf0d
 
cvsdist 5adf0d
+#ifdef USE_PAM
cvsdist 5adf0d
+# include <security/pam_appl.h>
cvsdist 5adf0d
+# include <security/pam_misc.h>
cvsdist 5adf0d
+# include <signal.h>
cvsdist 5adf0d
+# include <sys/wait.h>
cvsdist 5adf0d
+# include <sys/fsuid.h>
cvsdist 5adf0d
+#endif /* USE_PAM */
cvsdist 5adf0d
+
cvsdist 5adf0d
 #include "system.h"
cvsdist 5adf0d
 #include "dirname.h"
cvsdist 5adf0d
 
cvsdist 5adf0d
@@ -150,7 +168,9 @@
cvsdist 5adf0d
 /* The user to become if none is specified.  */
cvsdist 5adf0d
 #define DEFAULT_USER "root"
cvsdist 5adf0d
 
cvsdist 5adf0d
+#ifndef USE_PAM
cvsdist 5adf0d
 char *crypt ();
cvsdist 5adf0d
+#endif
cvsdist 5adf0d
 char *getpass ();
cvsdist 5adf0d
 char *getusershell ();
cvsdist 5adf0d
 void endusershell ();
cvsdist 5adf0d
@@ -158,8 +178,12 @@
cvsdist 5adf0d
 
cvsdist 5adf0d
 extern char **environ;
cvsdist 5adf0d
 
cvsdist 5adf0d
-static void run_shell (const char *, const char *, char **)
cvsdist 5adf0d
+static void run_shell (const char *, const char *, char **, const struct passwd *)
cvsdist 5adf0d
+#ifdef USE_PAM
cvsdist 5adf0d
+     ;
cvsdist 5adf0d
+#else
cvsdist 5adf0d
      ATTRIBUTE_NORETURN;
cvsdist 5adf0d
+#endif
cvsdist 5adf0d
 
cvsdist 5adf0d
 /* The name this program was run with.  */
cvsdist 5adf0d
 char *program_name;
cvsdist 5adf0d
@@ -271,7 +295,22 @@
cvsdist 5adf0d
 }
cvsdist 5adf0d
 #endif
cvsdist 5adf0d
 
cvsdist 5adf0d
+#ifdef USE_PAM
cvsdist 5adf0d
+static pam_handle_t *pamh = NULL;
cvsdist 5adf0d
+static int retval;
cvsdist 5adf0d
+static struct pam_conv conv = {
cvsdist 5adf0d
+  misc_conv,
cvsdist 5adf0d
+  NULL
cvsdist 5adf0d
+};
cvsdist 5adf0d
+
cvsdist 5adf0d
+#define PAM_BAIL_P if (retval) { \
cvsdist 5adf0d
+  pam_end(pamh, PAM_SUCCESS); \
cvsdist 5adf0d
+  return 0; \
cvsdist 5adf0d
+}
cvsdist 5adf0d
+#endif
cvsdist 5adf0d
+
cvsdist 5adf0d
 /* Ask the user for a password.
cvsdist 5adf0d
+   If PAM is in use, let PAM ask for the password if necessary.
cvsdist 5adf0d
    Return 1 if the user gives the correct password for entry PW,
cvsdist 5adf0d
    0 if not.  Return 1 without asking for a password if run by UID 0
cvsdist 5adf0d
    or if PW has an empty password.  */
cvsdist 5adf0d
@@ -279,6 +318,34 @@
cvsdist 5adf0d
 static int
cvsdist 5adf0d
 correct_password (const struct passwd *pw)
cvsdist 5adf0d
 {
cvsdist 5adf0d
+#ifdef USE_PAM
cvsdist 5adf0d
+  struct passwd *caller;
cvsdist 5adf0d
+  retval = pam_start(PROGRAM_NAME, pw->pw_name, &conv, &pamh);
cvsdist 5adf0d
+  PAM_BAIL_P;
cvsdist 5adf0d
+
cvsdist 5adf0d
+  if (getuid() != 0 && !isatty(0)) {
cvsdist 5adf0d
+	fprintf(stderr, "standard in must be a tty\n");
cvsdist 5adf0d
+	exit(1);
cvsdist 5adf0d
+  }
cvsdist 5adf0d
+
cvsdist 5adf0d
+  caller = getpwuid(getuid());
cvsdist 5adf0d
+  if(caller != NULL && caller->pw_name != NULL) {
cvsdist 5adf0d
+	  retval = pam_set_item(pamh, PAM_RUSER, caller->pw_name);
cvsdist 5adf0d
+	  PAM_BAIL_P;
cvsdist 5adf0d
+  }
cvsdist 5adf0d
+
cvsdist 5adf0d
+  retval = pam_authenticate(pamh, 0);
cvsdist 5adf0d
+  PAM_BAIL_P;
cvsdist 5adf0d
+  retval = pam_acct_mgmt(pamh, 0);
cvsdist 5adf0d
+  if (retval == PAM_NEW_AUTHTOK_REQD) {
cvsdist 5adf0d
+    /* password has expired.  Offer option to change it. */
cvsdist 5adf0d
+    retval = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
cvsdist 5adf0d
+    PAM_BAIL_P;
cvsdist 5adf0d
+  }
cvsdist 5adf0d
+  PAM_BAIL_P;
cvsdist 5adf0d
+  /* must be authenticated if this point was reached */
cvsdist 5adf0d
+  return 1;
cvsdist 5adf0d
+#else /* !USE_PAM */
cvsdist 5adf0d
   char *unencrypted, *encrypted, *correct;
cvsdist 5adf0d
 #if HAVE_GETSPNAM && HAVE_STRUCT_SPWD_SP_PWDP
cvsdist 5adf0d
   /* Shadow passwd stuff for SVR3 and maybe other systems.  */
cvsdist 5adf0d
@@ -303,6 +370,7 @@
cvsdist 5adf0d
   encrypted = crypt (unencrypted, correct);
cvsdist 5adf0d
   memset (unencrypted, 0, strlen (unencrypted));
cvsdist 5adf0d
   return strcmp (encrypted, correct) == 0;
cvsdist 5adf0d
+#endif /* !USE_PAM */
cvsdist 5adf0d
 }
cvsdist 5adf0d
 
cvsdist 5adf0d
 /* Update `environ' for the new shell based on PW, with SHELL being
cvsdist 5adf0d
@@ -312,16 +380,24 @@
cvsdist 5adf0d
 modify_environment (const struct passwd *pw, const char *shell)
cvsdist 5adf0d
 {
cvsdist 5adf0d
   char *term;
cvsdist 5adf0d
+  char *display;
cvsdist 5adf0d
+  char *xauthority;
cvsdist 5adf0d
 
cvsdist 5adf0d
   if (simulate_login)
cvsdist 5adf0d
     {
cvsdist 5adf0d
-      /* Leave TERM unchanged.  Set HOME, SHELL, USER, LOGNAME, PATH.
cvsdist 5adf0d
+      /* Leave TERM, DISPLAY, XAUTHORITY unchanged.  Set HOME, SHELL, USER, LOGNAME, PATH.
cvsdist 5adf0d
          Unset all other environment variables.  */
cvsdist 5adf0d
       term = getenv ("TERM");
cvsdist 5adf0d
+      display = getenv ("DISPLAY");
cvsdist 5adf0d
+      xauthority = getenv ("XAUTHORITY");
cvsdist 5adf0d
       environ = xmalloc (2 * sizeof (char *));
cvsdist 5adf0d
       environ[0] = 0;
cvsdist 5adf0d
       if (term)
cvsdist 5adf0d
 	xputenv (concat ("TERM", "=", term));
cvsdist 5adf0d
+      if (display)
cvsdist 5adf0d
+	xputenv (concat ("DISPLAY", "=", display));
cvsdist 5adf0d
+      if (xauthority)
cvsdist 5adf0d
+	xputenv (concat ("XAUTHORITY", "=", xauthority));
cvsdist 5adf0d
       xputenv (concat ("HOME", "=", pw->pw_dir));
cvsdist 5adf0d
       xputenv (concat ("SHELL", "=", shell));
cvsdist 5adf0d
       xputenv (concat ("USER", "=", pw->pw_name));
cvsdist 5adf0d
@@ -358,22 +434,73 @@
cvsdist 5adf0d
     error (EXIT_FAIL, errno, _("cannot set groups"));
cvsdist 5adf0d
   endgrent ();
cvsdist 5adf0d
 #endif
cvsdist 5adf0d
+#ifdef USE_PAM
cvsdist 5adf0d
+  retval = pam_setcred(pamh, PAM_ESTABLISH_CRED);
cvsdist 5adf0d
+  if (retval != PAM_SUCCESS)
cvsdist 5adf0d
+    error (1, 0, pam_strerror(pamh, retval));
cvsdist 5adf0d
+#endif /* USE_PAM */
cvsdist 5adf0d
   if (setgid (pw->pw_gid))
cvsdist 5adf0d
     error (EXIT_FAIL, errno, _("cannot set group id"));
cvsdist 5adf0d
   if (setuid (pw->pw_uid))
cvsdist 5adf0d
     error (EXIT_FAIL, errno, _("cannot set user id"));
cvsdist 5adf0d
 }
cvsdist 5adf0d
 
cvsdist 5adf0d
+#ifdef USE_PAM
cvsdist 5adf0d
+static int caught=0;
cvsdist 5adf0d
+/* Signal handler for parent process later */
cvsdist 5adf0d
+static void su_catch_sig(int sig)
cvsdist 5adf0d
+{
cvsdist 5adf0d
+  ++caught;
cvsdist 5adf0d
+}
cvsdist 5adf0d
+
cvsdist 5adf0d
+int
cvsdist 5adf0d
+pam_copyenv (pam_handle_t *pamh)
cvsdist 5adf0d
+{
cvsdist 5adf0d
+  char **env;
cvsdist 5adf0d
+
cvsdist 5adf0d
+  env = pam_getenvlist(pamh);
cvsdist 5adf0d
+  if(env) {
cvsdist 5adf0d
+    while(*env) {
cvsdist 5adf0d
+	xputenv(*env);
cvsdist 5adf0d
+	env++;
cvsdist 5adf0d
+    }
cvsdist 5adf0d
+  }
cvsdist 5adf0d
+  return(0);
cvsdist 5adf0d
+}
cvsdist 5adf0d
+#endif
cvsdist 5adf0d
+
cvsdist 5adf0d
 /* Run SHELL, or DEFAULT_SHELL if SHELL is empty.
cvsdist 5adf0d
    If COMMAND is nonzero, pass it to the shell with the -c option.
cvsdist 5adf0d
    If ADDITIONAL_ARGS is nonzero, pass it to the shell as more
cvsdist 5adf0d
    arguments.  */
cvsdist 5adf0d
 
cvsdist 5adf0d
 static void
cvsdist 5adf0d
-run_shell (const char *shell, const char *command, char **additional_args)
cvsdist 5adf0d
+run_shell (const char *shell, const char *command, char **additional_args, const struct passwd *pw)
cvsdist 5adf0d
 {
cvsdist 5adf0d
   const char **args;
cvsdist 5adf0d
   int argno = 1;
cvsdist 5adf0d
+#ifdef USE_PAM
cvsdist 5adf0d
+  int child;
cvsdist 5adf0d
+  sigset_t ourset;
cvsdist 5adf0d
+  int status;
cvsdist 5adf0d
+
cvsdist 5adf0d
+  retval = pam_open_session(pamh,0);
cvsdist 5adf0d
+  if (retval != PAM_SUCCESS) {
cvsdist 5adf0d
+    fprintf (stderr, "could not open session\n");
cvsdist 5adf0d
+    exit (1);
cvsdist 5adf0d
+  }
cvsdist 5adf0d
+
cvsdist 5adf0d
+/* do this at the last possible moment, because environment variables may
cvsdist 5adf0d
+   be passed even in the session phase
cvsdist 5adf0d
+*/
cvsdist 5adf0d
+  if(pam_copyenv(pamh) != PAM_SUCCESS)
cvsdist 5adf0d
+     fprintf (stderr, "error copying PAM environment\n");
cvsdist 5adf0d
+  
cvsdist 5adf0d
+  child = fork();
cvsdist 5adf0d
+  if (child == 0) {  /* child shell */
cvsdist 5adf0d
+  change_identity (pw);
cvsdist 5adf0d
+  pam_end(pamh, 0);
cvsdist 5adf0d
+#endif
cvsdist 5adf0d
 
cvsdist 5adf0d
   if (additional_args)
cvsdist 5adf0d
     args = xmalloc (sizeof (char *)
cvsdist 5adf0d
@@ -385,6 +512,9 @@
cvsdist 5adf0d
       char *arg0;
cvsdist 5adf0d
       char *shell_basename;
cvsdist 5adf0d
 
cvsdist 5adf0d
+      if(chdir(pw->pw_dir))
cvsdist 5adf0d
+	      error(0, errno, _("warning: cannot change directory to %s"), pw->pw_dir);
cvsdist 5adf0d
+
cvsdist 5adf0d
       shell_basename = base_name (shell);
cvsdist 5adf0d
       arg0 = xmalloc (strlen (shell_basename) + 2);
cvsdist 5adf0d
       arg0[0] = '-';
cvsdist 5adf0d
@@ -411,6 +541,61 @@
cvsdist 5adf0d
     error (0, errno, "%s", shell);
cvsdist 5adf0d
     exit (exit_status);
cvsdist 5adf0d
   }
cvsdist 5adf0d
+#ifdef USE_PAM
cvsdist 5adf0d
+  } else if (child == -1) {
cvsdist 5adf0d
+      fprintf(stderr, "can not fork user shell: %s", strerror(errno));
cvsdist 5adf0d
+      exit(1);
cvsdist 5adf0d
+  }
cvsdist 5adf0d
+  /* parent only */
cvsdist 5adf0d
+  sigfillset(&ourset);
cvsdist 5adf0d
+  if (sigprocmask(SIG_BLOCK, &ourset, NULL)) {
cvsdist 5adf0d
+    fprintf(stderr, "%s: signal malfunction\n", PROGRAM_NAME);
cvsdist 5adf0d
+    caught = 1;
cvsdist 5adf0d
+  }
cvsdist 5adf0d
+  if (!caught) {
cvsdist 5adf0d
+    struct sigaction action;
cvsdist 5adf0d
+    action.sa_handler = su_catch_sig;
cvsdist 5adf0d
+    sigemptyset(&action.sa_mask);
cvsdist 5adf0d
+    action.sa_flags = 0;
cvsdist 5adf0d
+    sigemptyset(&ourset);
cvsdist 5adf0d
+    if (sigaddset(&ourset, SIGTERM)
cvsdist 5adf0d
+        || sigaddset(&ourset, SIGALRM)
cvsdist 5adf0d
+        || sigaction(SIGTERM, &action, NULL)
cvsdist 5adf0d
+        || sigprocmask(SIG_UNBLOCK, &ourset, NULL)) {
cvsdist 5adf0d
+      fprintf(stderr, "%s: signal masking malfunction\n", PROGRAM_NAME);
cvsdist 5adf0d
+      caught = 1;
cvsdist 5adf0d
+    }
cvsdist 5adf0d
+  }
cvsdist 5adf0d
+  if (!caught) {
cvsdist 5adf0d
+    do {
cvsdist 5adf0d
+      int pid;
cvsdist 5adf0d
+
cvsdist 5adf0d
+      pid = waitpid(-1, &status, WUNTRACED);
cvsdist 5adf0d
+
cvsdist 5adf0d
+      if (WIFSTOPPED(status)) {
cvsdist 5adf0d
+          kill(getpid(), SIGSTOP);
cvsdist 5adf0d
+          /* once we get here, we must have resumed */
cvsdist 5adf0d
+          kill(pid, SIGCONT);
cvsdist 5adf0d
+      }
cvsdist 5adf0d
+    } while (WIFSTOPPED(status));
cvsdist 5adf0d
+  }
cvsdist 5adf0d
+
cvsdist 5adf0d
+  if (caught) {
cvsdist 5adf0d
+    fprintf(stderr, "\nSession terminated, killing shell...");
cvsdist 5adf0d
+    kill (child, SIGTERM);
cvsdist 5adf0d
+  }
cvsdist 5adf0d
+  retval = pam_close_session(pamh, 0);
cvsdist 5adf0d
+  PAM_BAIL_P;
cvsdist 5adf0d
+  retval = pam_end(pamh, PAM_SUCCESS);
cvsdist 5adf0d
+  PAM_BAIL_P;
cvsdist 5adf0d
+  if (caught) {
cvsdist 5adf0d
+    sleep(2);
cvsdist 5adf0d
+    kill(child, SIGKILL);
cvsdist 5adf0d
+    fprintf(stderr, " ...killed.\n");
cvsdist 5adf0d
+    exit(-1);
cvsdist 5adf0d
+  }
cvsdist 5adf0d
+  exit (WEXITSTATUS(status));
cvsdist 5adf0d
+#endif /* USE_PAM */
cvsdist 5adf0d
 }
cvsdist 5adf0d
 
cvsdist 5adf0d
 /* Return 1 if SHELL is a restricted shell (one not returned by
cvsdist 5adf0d
@@ -586,9 +771,13 @@
cvsdist 5adf0d
     }
cvsdist 5adf0d
   modify_environment (pw, shell);
cvsdist 5adf0d
 
cvsdist 5adf0d
+
cvsdist 5adf0d
+#ifdef USE_PAM
cvsdist 5adf0d
+  setfsuid(pw->pw_uid);
cvsdist 5adf0d
+  setfsgid(pw->pw_gid);
cvsdist 5adf0d
+#else
cvsdist 5adf0d
   change_identity (pw);
cvsdist 5adf0d
-  if (simulate_login && chdir (pw->pw_dir))
cvsdist 5adf0d
-    error (0, errno, _("warning: cannot change directory to %s"), pw->pw_dir);
cvsdist 5adf0d
+#endif
cvsdist 5adf0d
 
cvsdist 5adf0d
-  run_shell (shell, command, additional_args);
cvsdist 5adf0d
+  run_shell (shell, command, additional_args, pw);
cvsdist 5adf0d
 }
cvsdist 5adf0d
--- coreutils-5.2.0/configure.ac.pam	2004-02-23 17:40:54.000000000 +0000
cvsdist 5adf0d
+++ coreutils-5.2.0/configure.ac	2004-02-23 17:40:54.000000000 +0000
cvsdist 5adf0d
@@ -7,6 +7,13 @@
cvsdist 5adf0d
 
cvsdist 5adf0d
 AM_INIT_AUTOMAKE([1.8 gnits dist-bzip2])
cvsdist 5adf0d
 
cvsdist 5adf0d
+dnl Give the chance to enable PAM
cvsdist 5adf0d
+AC_ARG_ENABLE(pam, dnl
cvsdist 5adf0d
+[  --enable-pam              Enable use of the PAM libraries],
cvsdist 5adf0d
+[AC_DEFINE(USE_PAM, 1, [Define if you want to use PAM])
cvsdist 5adf0d
+LIB_PAM="-ldl -lpam -lpam_misc"
cvsdist 5adf0d
+AC_SUBST(LIB_PAM)])
cvsdist 5adf0d
+
cvsdist 5adf0d
 gl_DEFAULT_POSIX2_VERSION
cvsdist 5adf0d
 gl_USE_SYSTEM_EXTENSIONS
cvsdist 5adf0d
 jm_PERL
cvsdist 5adf0d
--- coreutils-5.2.0/config.hin.pam	2004-02-23 17:40:54.000000000 +0000
cvsdist 5adf0d
+++ coreutils-5.2.0/config.hin	2004-02-23 17:40:54.000000000 +0000
cvsdist 5adf0d
@@ -1365,6 +1365,9 @@
cvsdist 5adf0d
 /* Define if you want access control list support. */
cvsdist 5adf0d
 #undef USE_ACL
cvsdist 5adf0d
 
cvsdist 5adf0d
+/* Define if you want to use PAM */
cvsdist 5adf0d
+#undef USE_PAM
cvsdist 5adf0d
+
cvsdist 5adf0d
 /* Version number of package */
cvsdist 5adf0d
 #undef VERSION
cvsdist 5adf0d
 
cvsdist 460c93
--- coreutils-5.2.1/doc/coreutils.texi.pam	2004-05-18 11:41:14.026354659 +0100
cvsdist 460c93
+++ coreutils-5.2.1/doc/coreutils.texi	2004-05-18 11:48:27.056915340 +0100
cvsdist 460c93
@@ -11855,8 +11855,11 @@
cvsdist 460c93
 @findex syslog
cvsdist 460c93
 @command{su} can optionally be compiled to use @code{syslog} to report
cvsdist 460c93
 failed, and optionally successful, @command{su} attempts.  (If the system
cvsdist 460c93
-supports @code{syslog}.)  However, GNU @command{su} does not check if the
cvsdist 460c93
-user is a member of the @code{wheel} group; see below.
cvsdist 460c93
+supports @code{syslog}.)
cvsdist 460c93
+
cvsdist 460c93
+This version of @command{su} has support for using PAM for
cvsdist 460c93
+authentication.  You can edit @file{/etc/pam.d/su} to customize its
cvsdist 460c93
+behaviour.
cvsdist 460c93
 
cvsdist 460c93
 The program accepts the following options.  Also see @ref{Common options}.
cvsdist 460c93
 
cvsdist 460c93
@@ -11937,33 +11940,6 @@
cvsdist 460c93
 the exit status of the subshell otherwise
cvsdist 460c93
 @end display
cvsdist 460c93
 
cvsdist 460c93
-@cindex wheel group, not supported
cvsdist 460c93
-@cindex group wheel, not supported
cvsdist 460c93
-@cindex fascism
cvsdist 460c93
-@subsection Why GNU @command{su} does not support the @samp{wheel} group
cvsdist 460c93
-
cvsdist 460c93
-(This section is by Richard Stallman.)
cvsdist 460c93
-
cvsdist 460c93
-@cindex Twenex
cvsdist 460c93
-@cindex MIT AI lab
cvsdist 460c93
-Sometimes a few of the users try to hold total power over all the
cvsdist 460c93
-rest.  For example, in 1984, a few users at the MIT AI lab decided to
cvsdist 460c93
-seize power by changing the operator password on the Twenex system and
cvsdist 460c93
-keeping it secret from everyone else.  (I was able to thwart this coup
cvsdist 460c93
-and give power back to the users by patching the kernel, but I
cvsdist 460c93
-wouldn't know how to do that in Unix.)
cvsdist 460c93
-
cvsdist 460c93
-However, occasionally the rulers do tell someone.  Under the usual
cvsdist 460c93
-@command{su} mechanism, once someone learns the root password who
cvsdist 460c93
-sympathizes with the ordinary users, he or she can tell the rest.  The
cvsdist 460c93
-``wheel group'' feature would make this impossible, and thus cement the
cvsdist 460c93
-power of the rulers.
cvsdist 460c93
-
cvsdist 460c93
-I'm on the side of the masses, not that of the rulers.  If you are
cvsdist 460c93
-used to supporting the bosses and sysadmins in whatever they do, you
cvsdist 460c93
-might find this idea strange at first.
cvsdist 460c93
-
cvsdist 460c93
-
cvsdist 460c93
 @node Process control
cvsdist 460c93
 @chapter Process control
cvsdist 460c93