7130322 proftpd in the default configuration does not have required privileges
authortomas klacko - Sun Microsystems - Prague Czech Republic <tomas.klacko@oracle.com>
Mon, 27 Feb 2012 10:14:30 -0800
changeset 707 5953149bd743
parent 706 6e61f0012046
child 708 2cb7fdf18c3d
7130322 proftpd in the default configuration does not have required privileges
components/proftpd/mod_solaris_priv.c
--- a/components/proftpd/mod_solaris_priv.c	Fri Feb 24 13:30:24 2012 -0800
+++ b/components/proftpd/mod_solaris_priv.c	Mon Feb 27 10:14:30 2012 -0800
@@ -2,7 +2,7 @@
  * ProFTPD - FTP server daemon
  * Copyright (c) 1997, 1998 Public Flood Software
  * Copyright (c) 2003-2010 The ProFTPD Project team
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -169,6 +169,12 @@
 
     /* 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);
+
+    /* Needed to access /var/adm/wtmpx. */
+    priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_FILE_DAC_WRITE, NULL);
 }
 
 /* Setup priviledges before the user responds to the user prompt
@@ -181,13 +187,53 @@
     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 *p, *i;
+  priv_set_t *ps = NULL;
 
   if (!use_privs)
     return PR_DECLINED(cmd);
@@ -203,56 +249,55 @@
    * never need.
    */
 
-  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);
+  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);
 
-  p = priv_allocset();
-  priv_basicset(p);
+  priv_basicset(ps);
+
+  addset(ps, PRIV_NET_PRIVADDR);
+  addset(ps, PRIV_PROC_AUDIT);
 
-  priv_addset(p, PRIV_NET_PRIVADDR);
-  priv_addset(p, PRIV_PROC_AUDIT);
-
-  priv_delset(p, PRIV_PROC_EXEC);
-  priv_delset(p, PRIV_PROC_FORK);
-  priv_delset(p, PRIV_PROC_INFO);
-  priv_delset(p, PRIV_PROC_SESSION);
+  delset(ps, PRIV_PROC_EXEC);
+  delset(ps, PRIV_PROC_FORK);
+  delset(ps, PRIV_PROC_INFO);
+  delset(ps, 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.
    */
-  priv_addset(p, PRIV_PROC_SETID);
+  addset(ps, PRIV_PROC_SETID);
 
   /* Add any of the configurable privileges. */
   if (solaris_priv_flags & PRIV_USE_FILE_CHOWN)
-    priv_addset(p, PRIV_FILE_CHOWN);
+    addset(ps, PRIV_FILE_CHOWN);
 
   if (solaris_priv_flags & PRIV_USE_FILE_CHOWN_SELF)
-    priv_addset(p, PRIV_FILE_CHOWN_SELF);
+    addset(ps, PRIV_FILE_CHOWN_SELF);
 
   if (solaris_priv_flags & PRIV_USE_DAC_READ)
-    priv_addset(p, PRIV_FILE_DAC_READ);
+    addset(ps, PRIV_FILE_DAC_READ);
 
   if (solaris_priv_flags & PRIV_USE_DAC_WRITE)
-    priv_addset(p, PRIV_FILE_DAC_WRITE);
+    addset(ps, PRIV_FILE_DAC_WRITE);
 
   if (solaris_priv_flags & PRIV_USE_DAC_SEARCH)
-    priv_addset(p, PRIV_FILE_DAC_SEARCH);
+    addset(ps, PRIV_FILE_DAC_SEARCH);
 
   if (solaris_priv_flags & PRIV_USE_FILE_OWNER)
-    priv_addset(p, PRIV_FILE_OWNER);
+    addset(ps, PRIV_FILE_OWNER);
 
   if (solaris_priv_flags & PRIV_DROP_FILE_WRITE)
-    priv_delset(p, PRIV_FILE_WRITE);
+    delset(ps, PRIV_FILE_WRITE);
 
-  res = setppriv(PRIV_SET, PRIV_PERMITTED, p);
-  res = setppriv(PRIV_SET, PRIV_EFFECTIVE, p);
+  _setppriv(PRIV_SET, PRIV_PERMITTED, ps);
+  _setppriv(PRIV_SET, PRIV_EFFECTIVE, ps);
 
   if (setreuid(session.uid, session.uid) == -1) {
     pr_log_pri(PR_LOG_ERR, MOD_SOLARIS_PRIV_VERSION ": setreuid: %s",
@@ -262,21 +307,17 @@
   }
 
   if (!(solaris_priv_flags & PRIV_USE_SETID)) {
-    priv_delset(p, PRIV_PROC_SETID);
-    res = setppriv(PRIV_SET, PRIV_PERMITTED, p);
-    res = setppriv(PRIV_SET, PRIV_EFFECTIVE, p);
+    delset(ps, PRIV_PROC_SETID);
+    _setppriv(PRIV_SET, PRIV_PERMITTED, ps);
+    _setppriv(PRIV_SET, PRIV_EFFECTIVE, ps);
   }
 
+  priv_freeset(ps);
+
   pr_signals_unblock();
 
-  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 "
-      "capabilities failed, reverting to normal operation");
-  }
+  /* That's it!  Disable all further id switching */
+  session.disable_id_switching = TRUE;
 
   return PR_DECLINED(cmd);
 }