7162794 proftpd drops privilege too early breaking PAM assumptions
authorTomas Klacko <tomas.klacko@oracle.com>
Wed, 20 Jun 2012 02:45:16 -0700
changeset 881 b3186e256788
parent 880 a719e52810f9
child 882 e80d1fd74c8a
7162794 proftpd drops privilege too early breaking PAM assumptions
components/proftpd/mod_solaris_priv.c
--- a/components/proftpd/mod_solaris_priv.c	Tue Jun 19 11:24:46 2012 -0700
+++ b/components/proftpd/mod_solaris_priv.c	Wed Jun 20 02:45:16 2012 -0700
@@ -139,106 +139,13 @@
 /* Command handlers
  */
 
-/* The pre and post adat command handlers first enable
- * and then disable file_dac_read. This is done in order
- * for the mod_gss module to be able to read /etc/krb5/krb5.keytab,
- * when the proftpd server runs as user/group ftp/ftp.
- */
-MODRET solaris_priv_pre_adat(cmd_rec *cmd) {
-    priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_FILE_DAC_READ, NULL);
-    return PR_DECLINED(cmd);
-}
-
-MODRET solaris_priv_post_adat(cmd_rec *cmd) {
-    priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_FILE_DAC_READ, NULL);
-    return PR_DECLINED(cmd);
-}
-
-static void set_privs(void) {
-    /* This is for PAM code which decides to create an audit session
-     * when the user is logging into ftp as root.
-     */
-    priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_PROC_AUDIT, NULL);
-    priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_SYS_AUDIT, NULL);
-
-    /* Needed to call seteuid(). */
-    priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_PROC_SETID, NULL);
-
-    /* Needed to call settaskid(). */
-    priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_PROC_TASKID, NULL);
-
-    /* Needed to access /dev/urandom. */
-    priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_SYS_DEVICES, NULL);
-
-    /* Needed for pam_unix_cred to chown files. */
-    priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_FILE_CHOWN_SELF, NULL);
-    priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_FILE_CHOWN, NULL);
-    priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_FILE_OWNER, NULL);
-
-    /* Needed to access /var/adm/wtmpx. */
-    priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_FILE_DAC_WRITE, NULL);
-
-    /* Enable chroot for anonymous login. */
-    priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_PROC_CHROOT, NULL);
-}
-
-/* Setup priviledges before the user responds to the user prompt
- * from the ftp server so that a secure Kerberos session can be
- * established and also the user can login as root
- * when the ftp server is running as user/group ftp/ftp.
- */
-MODRET solaris_priv_pre_pass(cmd_rec *cmd) {
-    set_privs();
-    return PR_DECLINED(cmd);
-}
-
-static priv_set_t* allocset(void) {
-  priv_set_t* ret;
-
-  if ((ret = priv_allocset()) == NULL) {
-    pr_log_pri(PR_LOG_ERR, MOD_SOLARIS_PRIV_VERSION ": priv_allocset: %s",
-      strerror(errno));
-    pr_signals_unblock();
-    end_login(1);
-  }
-
-  return ret;
-}
-
-static void delset(priv_set_t *sp, const char *priv) {
-  if (priv_delset(sp, priv) != 0) {
-    pr_log_pri(PR_LOG_ERR, MOD_SOLARIS_PRIV_VERSION ": priv_delset: %s",
-      strerror(errno));
-    pr_signals_unblock();
-    end_login(1);
-  }
-}
-
-static void addset(priv_set_t *sp, const char *priv) {
-  if (priv_addset(sp, priv) != 0) {
-    pr_log_pri(PR_LOG_ERR, MOD_SOLARIS_PRIV_VERSION ": priv_addset: %s",
-      strerror(errno));
-    pr_signals_unblock();
-    end_login(1);
-  }
-}
-
-static void _setppriv(priv_op_t op, priv_ptype_t which, priv_set_t *set) {
-  if (setppriv(op, which, set) != 0) {
-    pr_log_pri(PR_LOG_ERR, MOD_SOLARIS_PRIV_VERSION ": setppriv: %s",
-      strerror(errno));
-    pr_signals_unblock();
-    end_login(1);
-  }
-}
-
 /* The POST_CMD handler for "PASS" is only called after PASS has
  * successfully completed, which means authentication is successful,
  * so we can "tweak" our root access down to almost nothing.
  */
 MODRET solaris_priv_post_pass(cmd_rec *cmd) {
   int res = 0;
-  priv_set_t *ps = NULL;
+  priv_set_t *p, *i;
 
   if (!use_privs)
     return PR_DECLINED(cmd);
@@ -254,75 +161,69 @@
    * never need.
    */
 
-  ps = allocset();
-  priv_basicset(ps);
-  delset(ps, PRIV_PROC_EXEC);
-  delset(ps, PRIV_PROC_FORK);
-  delset(ps, PRIV_PROC_INFO);
-  delset(ps, PRIV_PROC_SESSION);
-  _setppriv(PRIV_SET, PRIV_INHERITABLE, ps);
+  i = priv_allocset();
+  priv_basicset(i);
+  priv_delset(i, PRIV_PROC_EXEC);
+  priv_delset(i, PRIV_PROC_FORK);
+  priv_delset(i, PRIV_PROC_INFO);
+  priv_delset(i, PRIV_PROC_SESSION);
+  setppriv(PRIV_SET, PRIV_INHERITABLE, i);
 
-  priv_basicset(ps);
+  p = priv_allocset();
+  priv_basicset(p);
 
-  addset(ps, PRIV_NET_PRIVADDR);
-  addset(ps, PRIV_PROC_AUDIT);
+  priv_addset(p, PRIV_NET_PRIVADDR);
+  priv_addset(p, PRIV_PROC_AUDIT);
 
-  delset(ps, PRIV_PROC_EXEC);
-  delset(ps, PRIV_PROC_FORK);
-  delset(ps, PRIV_PROC_INFO);
-  delset(ps, PRIV_PROC_SESSION);
+  priv_delset(p, PRIV_PROC_EXEC);
+  priv_delset(p, PRIV_PROC_FORK);
+  priv_delset(p, PRIV_PROC_INFO);
+  priv_delset(p, PRIV_PROC_SESSION);
 
-  /* If the proftpd process is not running as root, but as user ftp,
-   * then this is necessary in order to make the setreuid work.
-   * Without this, the setreuid would fail. The PRIV_PROC_SETID privilege 
-   * is removed afterwards.
-   */
-  addset(ps, PRIV_PROC_SETID);
+  if (solaris_priv_flags & PRIV_USE_SETID)
+    priv_addset(p, PRIV_PROC_SETID);
 
   /* Add any of the configurable privileges. */
   if (solaris_priv_flags & PRIV_USE_FILE_CHOWN)
-    addset(ps, PRIV_FILE_CHOWN);
+    priv_addset(p, PRIV_FILE_CHOWN);
 
   if (solaris_priv_flags & PRIV_USE_FILE_CHOWN_SELF)
-    addset(ps, PRIV_FILE_CHOWN_SELF);
+    priv_addset(p, PRIV_FILE_CHOWN_SELF);
 
   if (solaris_priv_flags & PRIV_USE_DAC_READ)
-    addset(ps, PRIV_FILE_DAC_READ);
+    priv_addset(p, PRIV_FILE_DAC_READ);
 
   if (solaris_priv_flags & PRIV_USE_DAC_WRITE)
-    addset(ps, PRIV_FILE_DAC_WRITE);
+    priv_addset(p, PRIV_FILE_DAC_WRITE);
 
   if (solaris_priv_flags & PRIV_USE_DAC_SEARCH)
-    addset(ps, PRIV_FILE_DAC_SEARCH);
+    priv_addset(p, PRIV_FILE_DAC_SEARCH);
 
   if (solaris_priv_flags & PRIV_USE_FILE_OWNER)
-    addset(ps, PRIV_FILE_OWNER);
+    priv_addset(p, PRIV_FILE_OWNER);
 
   if (solaris_priv_flags & PRIV_DROP_FILE_WRITE)
-    delset(ps, PRIV_FILE_WRITE);
+    priv_delset(p, PRIV_FILE_WRITE);
 
-  _setppriv(PRIV_SET, PRIV_PERMITTED, ps);
-  _setppriv(PRIV_SET, PRIV_EFFECTIVE, ps);
+  res = setppriv(PRIV_SET, PRIV_PERMITTED, p);
+  res = setppriv(PRIV_SET, PRIV_EFFECTIVE, p);
 
   if (setreuid(session.uid, session.uid) == -1) {
     pr_log_pri(PR_LOG_ERR, MOD_SOLARIS_PRIV_VERSION ": setreuid: %s",
-      strerror(errno));
+	strerror(errno));
     pr_signals_unblock();
     end_login(1);
   }
-
-  if (!(solaris_priv_flags & PRIV_USE_SETID)) {
-    delset(ps, PRIV_PROC_SETID);
-    _setppriv(PRIV_SET, PRIV_PERMITTED, ps);
-    _setppriv(PRIV_SET, PRIV_EFFECTIVE, ps);
-  }
-
-  priv_freeset(ps);
-
   pr_signals_unblock();
 
-  /* That's it!  Disable all further id switching */
-  session.disable_id_switching = TRUE;
+  if (res != -1) {
+    /* That's it!  Disable all further id switching */
+    session.disable_id_switching = TRUE;
+
+  } else {
+    pr_log_pri(PR_LOG_NOTICE, MOD_SOLARIS_PRIV_VERSION ": attempt to configure "
+      "privileges failed, reverting to normal operation");
+  }
 
   return PR_DECLINED(cmd);
 }
@@ -331,7 +232,7 @@
  */
 
 static int solaris_priv_sess_init(void) {
-  /* Check to see if the lowering of capabilities has been disabled in the
+  /* Check to see if the lowering of privileges has been disabled in the
    * configuration file.
    */
   if (use_privs) {
@@ -341,12 +242,12 @@
     if (solaris_priv_engine &&
         *solaris_priv_engine == FALSE) {
       pr_log_debug(DEBUG3, MOD_SOLARIS_PRIV_VERSION
-        ": lowering of capabilities disabled");
+        ": lowering of privileges disabled");
       use_privs = FALSE;
     }
   }
 
-  /* Check for which specific capabilities to include/exclude. */
+  /* Check for which specific privileges to include/exclude. */
   if (use_privs) {
     int use_setuid = FALSE;
     config_rec *c;
@@ -392,7 +293,7 @@
     /* We also need to check for things which want to revoke root privs
      * altogether: mod_exec, mod_sftp, and the RootRevoke directive.
      * Revoking root privs completely requires the SETUID/SETGID
-     * capabilities.
+     * privileges.
      */
 
     if (use_setuid == FALSE &&
@@ -448,9 +349,6 @@
 };
 
 static cmdtable solaris_priv_cmdtab[] = {
-  { PRE_CMD, C_ADAT, G_NONE, solaris_priv_pre_adat, FALSE, FALSE },
-  { POST_CMD, C_ADAT, G_NONE, solaris_priv_post_adat, FALSE, FALSE },
-  { PRE_CMD, C_PASS, G_NONE, solaris_priv_pre_pass, FALSE, FALSE },
   { POST_CMD, C_PASS, G_NONE, solaris_priv_post_pass, FALSE, FALSE },
   { 0, NULL }
 };
@@ -462,7 +360,7 @@
   0x20,
 
   /* Module name */
-  "cap",
+  "privileges",
 
   /* Module configuration handler table */
   solaris_priv_conftab,