[sork] PATCH: LDAP Vacation without anonymous DN searching

Douglas C. Stephens stephens at ameslab.gov
Sat Jan 26 06:05:31 UTC 2008


This is my first post to this list.

Our security policy on the LDAP directory we use for email does not permit
anonymous binds.  This conflicts with apparent assumptions in the SORK
Vacation LDAP driver, as evidenced by this wording from config/conf.xml:

"The DN used to bind to the LDAP server. If empty, we will bind anonymously
  to search for the user DN and bind with the user name and password when
  setting the vacation message, see below."

 From reading this language, reading the code, and experimenting with the
module, it seemed the author of the LDAP driver assumed the following:

* Searches would be permitted for anonymous binds, or
* An account would be available with ACL privileges in the directory to
   search, read, and write to the necessary attributes.

This inference was confirmed during testing by rotating the binddn value
through the following states:

* Blank,
* Containing the DN of an account with only search/read privileges,
* Containing the DN of an account with full search/read/write privileges in
   the directory.

To address this, my options were:

1. Discontinue roll-out of a Vacation module integrated into the IMP webmail
    system I've run for the past eight years, and choose another webmail and/or
    Vacation web interface.
2. Configure an account with ACL privileges in my directory to search, read,
    and write the necessary attributes.
3. Alter the security policy on the LDAP directory to permit anonymous binds.
4. Patch the SORK Vacation code.

For an assortment of reasons, option (4) was selected.

Appended below is a tested and relatively straightforward patch for the SORK
module vacation-h3-3.0.1 that provides the following features:

* A non-anonymous bind for searching a user DN in the _lookupdn() method,
   while at the same performing the LDAP attribute changes while bound as the
   currently logged-in user's DN.
* A boolean module configuration variable to control activation of this DN
   search mode.  Setting this variable value to FALSE was tested to correctly
   revert to the unpatched logic for the binddn setting.
* Debugging output now shows what DN, if any, was used to bind with to perform
   the search in _lookupdn().

After this patch is applied, it is necessary to regenerate a new conf.php
module configuration file.

I ask that this patch be added to the next release of the SORK Vacation
module so that others who find themselves in a similar situation with their
LDAP directory may benefit.  Also, I am looking forward to Ingo 2.x with its
integration of the SORK backend drivers, so it would be quite fine to see this
patch be included in those drivers.

Thanks.

------------------------------------------------------------------------------
--- config/conf.xml.1   2006-10-13 11:03:33.000000000 -0500
+++ config/conf.xml     2008-01-25 17:50:06.000000000 -0600
@@ -213,6 +213,10 @@
          vacation message, see below."/>
          <configstring name="bindpw" required="false" desc="The 
password used to
          bind to the LDAP server"/>
+        <configboolean name="noanonsearch" required="false" desc="No anonymous
+        searches allowed?  If so, then will bind with the given DN 
to search for
+        the user DN, and bind as the user when setting the vacation message.">
+        no</configboolean>
         </case>
         <case name="true" desc="Yes, but with the domain stripped from the
         username">
@@ -222,6 +226,10 @@
          vacation message, see below."/>
          <configstring name="bindpw" required="false" desc="The 
password used to
          bind to the LDAP server"/>
+        <configboolean name="noanonsearch" required="false" desc="No anonymous
+        searches allowed?  If so, then will bind with the given DN 
to search for
+        the user DN, and bind as the user when setting the vacation message.">
+        no</configboolean>
         </case>
        </configswitch>
       </configsection>
--- lib/Driver/ldap.php.1       2007-01-02 07:55:22.000000000 -0600
+++ lib/Driver/ldap.php 2008-01-25 23:24:33.000000000 -0600
@@ -88,7 +88,7 @@
                              $this->_params[$realm]['version']);
          }

-        if (!empty($this->_params[$realm]['binddn'])) {
+        if (!$this->_params[$realm]['noanonsearch'] && 
!empty($this->_params[$realm]['binddn'])) {
              $result = @ldap_bind($this->_ds, 
$this->_params[$realm]['binddn'], $this->_params[$realm]['bindpw']);
          } elseif (!is_null($userdn)) {
              $result = @ldap_bind($this->_ds, $userdn, $password);
@@ -148,8 +148,19 @@
       */
      function _lookupdn($user, $realm)
      {
-        // Bind as guest.
-        $this->_connect();
+
+        if ($this->_params[$realm]['noanonsearch']) {
+            if (!empty($this->_params[$realm]['binddn'])) {
+                // Bind as the configured DN in binddn.
+                $this->_connect($this->_params[$realm]['binddn'], 
$this->_params[$realm]['bindpw']);
+            } else {
+                // Bind as guest.
+                $this->_connect();
+            }
+        } else {
+            // Bind as guest.
+            $this->_connect();
+        }

          // Construct search.
          $search = $this->_params[$realm]['uid'] . '=' . $user;
@@ -158,10 +169,15 @@
          }

          /* Log the query at a DEBUG log level. */
-        Horde::logMessage(sprintf('LDAP query by 
Vacation_Driver_ldap::_lookupdn(): root = "%s"; filter = "%s"; timelimit = %d',
+        if (!empty($this->_params[$realm]['binddn'])) {
+          Horde::logMessage(sprintf('LDAP query by 
Vacation_Driver_ldap::_lookupdn(): binddn = "%s"; root = "%s"; filter 
= "%s"; timelimit = %d',
+                                  $this->_params[$realm]['binddn'], 
$this->_params[$realm]['basedn'], $search, $this->_params[$realm]['timeout']),
+                          __FILE__, __LINE__, PEAR_LOG_DEBUG);
+        } else {
+          Horde::logMessage(sprintf('LDAP query by 
Vacation_Driver_ldap::_lookupdn(): root = "%s"; filter = "%s"; timelimit = %d',
                                    $this->_params[$realm]['basedn'], 
$search, $this->_params[$realm]['timeout']),
                            __FILE__, __LINE__, PEAR_LOG_DEBUG);
-
+        }
          // Get userdn.
          $result = @ldap_search($this->_ds, 
$this->_params[$realm]['basedn'], $search, array(), 0, 0, 
$this->_params[$realm]['timeout']);
          if (!$result ||
------------------------------------------------------------------------------





More information about the sork mailing list