[sudo-workers] LDAP sudoers search Performance

Thomas, Matthew (GE Tech Infra, US) matthewt.thomas at ge.com
Wed Mar 16 13:19:05 EDT 2011


 

With the current ldap search that sudoers performs there can be performance
issues when netgroups are used as the value for sudoUser. I have seen delays
over 10 minutes with just 1000 entries in the sudoers OU. This can be
optimized to some degree with support for a search filter, similar to the
service search descriptor functionality in a DUAConfigProfile for Solaris. 

 

I have modified the ldap.c which came with 1.7.5rc1 to implement a
sudoers_search_filter in /etc/ldap.c. The Patch for the ldap.c and sudoers
man page is below. 

 

Could this change be incorporated in the a future version of sudo?

 

Thanks,

Matt Thomas

 

 

*** ../sudo-1.7.5rc1/sudoers.ldap.pod   Tue Feb  1 14:28:56 2011

--- ./sudoers.ldap.pod  Thu Mar  3 10:28:03 2011

***************

*** 369,374 ****

--- 369,380 ----

  C<example.com>.  Multiple B<SUDOERS_BASE> lines may be specified,

  in which case they are queried in the order specified.

 

+ =item B<SUDOERS_SEARCH_FILTER> ldap_filter

+

+ A ldap filter which is used when performing B<sudo> LDAP queries.

+ Typically this is of the form C<attribute=value> or

+ C<(&(attribute=value)(attribute2=value2))>.

+

  =item B<SUDOERS_TIMED> on/true/yes/off/false/no

 

  Whether or not to evaluate the C<sudoNotBefore> and C<sudoNotAfter>

 

 

 

 

*** ldap.c.orig Thu Feb 24 15:25:15 2011

--- ldap.c      Thu Mar  3 10:54:43 2011

***************

*** 201,206 ****

--- 201,207 ----

      char *bindpw;

      char *rootbinddn;

      struct ldap_config_list_str *base;

+     char *search_filter;

      char *ssl;

      char *tls_cacertfile;

      char *tls_cacertdir;

***************

*** 285,290 ****

--- 286,292 ----

      { "rootbinddn", CONF_STR, FALSE, -1, &ldap_conf.rootbinddn },

      { "sudoers_base", CONF_LIST_STR, FALSE, -1, &ldap_conf.base },

      { "sudoers_timed", CONF_BOOL, FALSE, -1, &ldap_conf.timed },

+     { "sudoers_search_filter", CONF_STR, FALSE, -1,
&ldap_conf.search_filter },

  #ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S

      { "use_sasl", CONF_BOOL, FALSE, -1, &ldap_conf.use_sasl },

      { "sasl_auth_id", CONF_STR, FALSE, -1, &ldap_conf.sasl_auth_id },

***************

*** 976,982 ****

--- 978,1029 ----

      return bytes;

  }

 

+

  /*

+  * Builds up a filter to search for default settings

+  */

+ static char *

+ sudo_ldap_build_default_filter()

+ {

+     char *buf;

+     size_t sz;

+

+     sz = 14;

+

+     if(ldap_conf.search_filter){

+       sz += strlen(ldap_conf.search_filter) + 3;

+       if(ldap_conf.search_filter[0] != '('){

+               sz += 2;

+       }

+     }

+

+     buf = emalloc(sz);

+     *buf = '\0';

+

+     if (ldap_conf.search_filter)

+       (void) strlcpy(buf, "(&", sz);

+

+     if(ldap_conf.search_filter){

+       if(ldap_conf.search_filter[0] != '('){

+               (void) strlcat(buf, "(", sz);

+       }

+       (void) strlcat(buf, ldap_conf.search_filter, sz);

+

+       if(ldap_conf.search_filter[0] != '('){

+               (void) strlcat(buf, ")", sz);

+       }

+     }

+

+     (void) strlcat(buf,"(cn=defaults)",sz);

+

+     if (ldap_conf.search_filter){

+       strlcat(buf, ")", sz); /* closes the global AND */

+     }

+

+     return buf;

+ }

+

+ /*

   * Builds up a filter to check against LDAP.

   */

  static char *

***************

*** 988,995 ****

      size_t sz;

      int i;

 

      /* Start with (|(sudoUser=USERNAME)(sudoUser=ALL)) + NUL */

!     sz = 29 + strlen(pw->pw_name);

 

      /* Add space for groups */

      if ((grp = sudo_getgrgid(pw->pw_gid)) != NULL) {

--- 1035,1051 ----

      size_t sz;

      int i;

 

+     sz = 0;

+     /* Start with LDAP Search Descriptor length + 3 */

+     if(ldap_conf.search_filter){

+       sz += strlen(ldap_conf.search_filter) + 3;

+       if(ldap_conf.search_filter[0] != '('){

+               sz += 2;

+       }

+     }

+

      /* Start with (|(sudoUser=USERNAME)(sudoUser=ALL)) + NUL */

!     sz += 29 + strlen(pw->pw_name);

 

      /* Add space for groups */

      if ((grp = sudo_getgrgid(pw->pw_gid)) != NULL) {

***************

*** 1014,1023 ****

      /*

       * If timed, start a global AND clause that will have the time limits

       * as the second leg.

       */

!     if (ldap_conf.timed)

        (void) strlcpy(buf, "(&", sz);

 

      /* Global OR + sudoUser=user_name filter */

      (void) strlcat(buf, "(|(sudoUser=", sz);

      (void) strlcat(buf, pw->pw_name, sz);

--- 1070,1091 ----

      /*

       * If timed, start a global AND clause that will have the time limits

       * as the second leg.

+      * check for searchdescriptor as well

       */

!     if (ldap_conf.timed || ldap_conf.search_filter)

        (void) strlcpy(buf, "(&", sz);

 

+     if(ldap_conf.search_filter){

+       if(ldap_conf.search_filter[0] != '('){

+               (void) strlcat(buf, "(", sz);

+       }

+       (void) strlcat(buf, ldap_conf.search_filter, sz);

+

+       if(ldap_conf.search_filter[0] != '('){

+               (void) strlcat(buf, ")", sz);

+       }

+     }

+

      /* Global OR + sudoUser=user_name filter */

      (void) strlcat(buf, "(|(sudoUser=", sz);

      (void) strlcat(buf, pw->pw_name, sz);

***************

*** 1053,1058 ****

--- 1121,1129 ----

        sudo_ldap_timefilter(timebuffer, sizeof(timebuffer));

        strlcat(buf, timebuffer, sz);

      }

+     else if (ldap_conf.search_filter){

+       strlcat(buf, ")", sz); /* closes the global OR */

+     }

      strlcat(buf, ")", sz); /* closes the global OR or the global AND */

 

      return buf;

***************

*** 1065,1071 ****

--- 1136,1179 ----

  sudo_ldap_build_pass2()

  {

      char *buf, timebuffer[TIMEFILTER_LENGTH];

+     size_t sz;

 

+     sz = 14;

+     /* Start with LDAP Search Descriptor length + 3 */

+     if(ldap_conf.search_filter){

+       sz += strlen(ldap_conf.search_filter) + 3;

+       if(ldap_conf.search_filter[0] != '('){

+               sz += 2;

+       }

+     }

+

+     /* If timed, add space for time limits. */

+     if (ldap_conf.timed)

+         sz += TIMEFILTER_LENGTH;

+

+     buf = emalloc(sz);

+     *buf = '\0';

+

+     /*

+      * If timed, start a global AND clause that will have the time limits

+      * as the second leg.

+      * check for searchdescriptor as well

+      */

+     if (ldap_conf.timed || ldap_conf.search_filter)

+         (void) strlcpy(buf, "(&", sz);

+

+     if(ldap_conf.search_filter){

+       if(ldap_conf.search_filter[0] != '('){

+               (void) strlcat(buf, "(", sz);

+       }

+       (void) strlcat(buf, ldap_conf.search_filter, sz);

+       if(ldap_conf.search_filter[0] != '('){

+               (void) strlcat(buf, ")", sz);

+       }

+     }

+

+     (void) strlcat(buf, "(sudoUser=+*)", sz);

+

      if (ldap_conf.timed) {

        /*

         * If timed, use a global AND clause that has the time limit as

***************

*** 1072,1083 ****

         * as the second leg.

         */

        sudo_ldap_timefilter(timebuffer, sizeof(timebuffer));

!       easprintf(&buf, "(&(sudoUser=+*)%s)", timebuffer);

!     } else {

!       /* No time limit, just the netgroup selection. */

!       buf = estrdup("sudoUser=+*");

      }

 

      return buf;

  }

 

--- 1180,1191 ----

         * as the second leg.

         */

        sudo_ldap_timefilter(timebuffer, sizeof(timebuffer));

!       strlcat(buf, timebuffer, sz);

      }

 

+     if (ldap_conf.timed || ldap_conf.search_filter)

+       strlcat(buf, ")", sz);

+

      return buf;

  }

 

***************

*** 1242,1247 ****

--- 1350,1358 ----

            fprintf(stderr, "sudoers_base     %s\n",

                "(NONE) <---Sudo will ignore ldap)");

        }

+       if (ldap_conf.search_filter){

+       fprintf(stderr,"Search_Filter  %s\n",ldap_conf.search_filter);

+       }

        fprintf(stderr, "binddn           %s\n", ldap_conf.binddn ?

            ldap_conf.binddn : "(anonymous)");

        fprintf(stderr, "bindpw           %s\n", ldap_conf.bindpw ?

***************

*** 1414,1419 ****

--- 1525,1531 ----

      LDAP *ld;

      LDAPMessage *entry, *result;

      char *prefix;

+     char *filt;

      int rc, count = 0;

 

      if (handle == NULL || handle->ld == NULL)

***************

*** 1420,1425 ****

--- 1532,1539 ----

        goto done;

      ld = handle->ld;

 

+     filt = sudo_ldap_build_default_filter();

+

      for (base = ldap_conf.base; base != NULL; base = base->next) {

        if (ldap_conf.timeout > 0) {

            tv.tv_sec = ldap_conf.timeout;

***************

*** 1428,1434 ****

        }

        result = NULL;

        rc = ldap_search_ext_s(ld, base->val, LDAP_SCOPE_SUBTREE,

!           "cn=defaults", NULL, 0, NULL, NULL, tvp, 0, &result);

        if (rc == LDAP_SUCCESS && (entry = ldap_first_entry(ld, result))) {

            bv = ldap_get_values_len(ld, entry, "sudoOption");

            if (bv != NULL) {

--- 1542,1548 ----

        }

        result = NULL;

        rc = ldap_search_ext_s(ld, base->val, LDAP_SCOPE_SUBTREE,

!           filt,NULL, 0, NULL, NULL, tvp, 0, &result);

        if (rc == LDAP_SUCCESS && (entry = ldap_first_entry(ld, result))) {

            bv = ldap_get_values_len(ld, entry, "sudoOption");

            if (bv != NULL) {

***************

*** 1447,1452 ****

--- 1561,1567 ----

        if (result)

            ldap_msgfree(result);

      }

+     efree(filt);

  done:

      return count;

  }

***************

*** 2080,2090 ****

--- 2195,2209 ----

      LDAP *ld;

      LDAPMessage *entry, *result;

      int rc;

+     char *filt;

 

      if (handle == NULL || handle->ld == NULL)

        return -1;

      ld = handle->ld;

 

+     filt = sudo_ldap_build_default_filter();

+     DPRINTF(("Looking for cn=defaults: %s", filt), 1);

+

      for (base = ldap_conf.base; base != NULL; base = base->next) {

        if (ldap_conf.timeout > 0) {

            tv.tv_sec = ldap_conf.timeout;

***************

*** 2093,2099 ****

        }

        result = NULL;

        rc = ldap_search_ext_s(ld, base->val, LDAP_SCOPE_SUBTREE,

!           "cn=defaults", NULL, 0, NULL, NULL, NULL, 0, &result);

        if (rc == LDAP_SUCCESS && (entry = ldap_first_entry(ld, result))) {

            DPRINTF(("found:%s", ldap_get_dn(ld, entry)), 1);

            sudo_ldap_parse_options(ld, entry);

--- 2212,2218 ----

        }

        result = NULL;

        rc = ldap_search_ext_s(ld, base->val, LDAP_SCOPE_SUBTREE,

!           filt,NULL, 0, NULL, NULL, tvp, 0, &result);

        if (rc == LDAP_SUCCESS && (entry = ldap_first_entry(ld, result))) {

            DPRINTF(("found:%s", ldap_get_dn(ld, entry)), 1);

            sudo_ldap_parse_options(ld, entry);

***************

*** 2103,2108 ****

--- 2222,2228 ----

        if (result)

            ldap_msgfree(result);

      }

+     efree(filt);

 

      return 0;

  }



More information about the sudo-workers mailing list