[BACK]Return to ldap.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / sudo

Diff for /src/usr.bin/sudo/Attic/ldap.c between version 1.8 and 1.9

version 1.8, 2008/07/31 16:44:03 version 1.9, 2008/11/14 11:58:08
Line 45 
Line 45 
 # include <unistd.h>  # include <unistd.h>
 #endif /* HAVE_UNISTD_H */  #endif /* HAVE_UNISTD_H */
 #include <ctype.h>  #include <ctype.h>
 #include <limits.h>  
 #include <pwd.h>  #include <pwd.h>
 #include <grp.h>  #include <grp.h>
 #include <netinet/in.h>  #include <netinet/in.h>
 #include <arpa/inet.h>  #include <arpa/inet.h>
 #include <netdb.h>  #include <netdb.h>
 #ifdef HAVE_ERR_H  
 # include <err.h>  
 #else  
 # include "emul/err.h"  
 #endif /* HAVE_ERR_H */  
 #include <errno.h>  
 #ifdef HAVE_LBER_H  #ifdef HAVE_LBER_H
 # include <lber.h>  # include <lber.h>
 #endif  #endif
Line 66 
Line 59 
 #elif defined(HAVE_MPS_LDAP_SSL_H)  #elif defined(HAVE_MPS_LDAP_SSL_H)
 # include <mps/ldap_ssl.h>  # include <mps/ldap_ssl.h>
 #endif  #endif
   #ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S
   # ifdef HAVE_SASL_SASL_H
   #  include <sasl/sasl.h>
   # else
   #  include <sasl.h>
   # endif
   # if HAVE_GSS_KRB5_CCACHE_NAME
   #  if defined(HAVE_GSSAPI_GSSAPI_KRB5_H)
   #   include <gssapi/gssapi.h>
   #   include <gssapi/gssapi_krb5.h>
   #  elif defined(HAVE_GSSAPI_GSSAPI_H)
   #   include <gssapi/gssapi.h>
   #  else
   #   include <gssapi.h>
   #  endif
   # endif
   #endif
   
 #include "sudo.h"  #include "sudo.h"
 #include "parse.h"  #include "parse.h"
   #include "lbuf.h"
   
 #ifndef lint  #ifndef lint
 __unused static const char rcsid[] = "$Sudo: ldap.c,v 1.11.2.38 2008/04/11 14:03:51 millert Exp $";  __unused static const char rcsid[] = "$Sudo: ldap.c,v 1.100 2008/04/23 12:30:07 millert Exp $";
 #endif /* lint */  #endif /* lint */
   
 #ifndef LINE_MAX  
 # define LINE_MAX 2048  
 #endif  
   
 #ifndef LDAP_OPT_SUCCESS  #ifndef LDAP_OPT_SUCCESS
 # define LDAP_OPT_SUCCESS LDAP_SUCCESS  # define LDAP_OPT_SUCCESS LDAP_SUCCESS
 #endif  #endif
Line 86 
Line 93 
 # define LDAPS_PORT 636  # define LDAPS_PORT 636
 #endif  #endif
   
 #define DPRINTF(args, level)    if (ldap_conf.debug >= level) warnx args  #if defined(HAVE_LDAP_SASL_INTERACTIVE_BIND_S) && !defined(LDAP_SASL_QUIET)
   # define LDAP_SASL_QUIET        0
   #endif
   
   #ifndef HAVE_LDAP_UNBIND_EXT_S
   #define ldap_unbind_ext_s(a, b, c)      ldap_unbind_s(a)
   #endif
   
   #ifndef HAVE_LDAP_SEARCH_EXT_S
   #define ldap_search_ext_s(a, b, c, d, e, f, g, h, i, j, k)              \
           ldap_search_s(a, b, c, d, e, f, k)
   #endif
   
   #define LDAP_FOREACH(var, ld, res)                                      \
       for ((var) = ldap_first_entry((ld), (res));                         \
           (var) != NULL;                                                  \
           (var) = ldap_next_entry((ld), (var)))
   
   #define DPRINTF(args, level)    if (ldap_conf.debug >= level) warningx args
   
 #define CONF_BOOL       0  #define CONF_BOOL       0
 #define CONF_INT        1  #define CONF_INT        1
 #define CONF_STR        2  #define CONF_STR        2
Line 104 
Line 129 
 };  };
   
 /* ldap configuration structure */  /* ldap configuration structure */
 struct ldap_config {  static struct ldap_config {
     int port;      int port;
     int version;      int version;
     int debug;      int debug;
Line 112 
Line 137 
     int tls_checkpeer;      int tls_checkpeer;
     int timelimit;      int timelimit;
     int bind_timelimit;      int bind_timelimit;
       int use_sasl;
       int rootuse_sasl;
     int ssl_mode;      int ssl_mode;
     char *host;      char *host;
     char *uri;      char *uri;
Line 126 
Line 153 
     char *tls_cipher_suite;      char *tls_cipher_suite;
     char *tls_certfile;      char *tls_certfile;
     char *tls_keyfile;      char *tls_keyfile;
       char *sasl_auth_id;
       char *rootsasl_auth_id;
       char *sasl_secprops;
       char *krb5_ccname;
 } ldap_conf;  } ldap_conf;
   
 struct ldap_config_table ldap_conf_table[] = {  static struct ldap_config_table ldap_conf_table[] = {
     { "sudoers_debug", CONF_INT, FALSE, -1, &ldap_conf.debug },      { "sudoers_debug", CONF_INT, FALSE, -1, &ldap_conf.debug },
     { "host", CONF_STR, FALSE, -1, &ldap_conf.host },      { "host", CONF_STR, FALSE, -1, &ldap_conf.host },
     { "port", CONF_INT, FALSE, -1, &ldap_conf.port },      { "port", CONF_INT, FALSE, -1, &ldap_conf.port },
Line 188 
Line 219 
     { "bindpw", CONF_STR, FALSE, -1, &ldap_conf.bindpw },      { "bindpw", CONF_STR, FALSE, -1, &ldap_conf.bindpw },
     { "rootbinddn", CONF_STR, FALSE, -1, &ldap_conf.rootbinddn },      { "rootbinddn", CONF_STR, FALSE, -1, &ldap_conf.rootbinddn },
     { "sudoers_base", CONF_STR, FALSE, -1, &ldap_conf.base },      { "sudoers_base", CONF_STR, FALSE, -1, &ldap_conf.base },
   #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 },
       { "rootuse_sasl", CONF_BOOL, FALSE, -1, &ldap_conf.rootuse_sasl },
       { "rootsasl_auth_id", CONF_STR, FALSE, -1, &ldap_conf.rootsasl_auth_id },
   # ifdef LDAP_OPT_X_SASL_SECPROPS
       { "sasl_secprops", CONF_STR, TRUE, LDAP_OPT_X_SASL_SECPROPS,
           &ldap_conf.sasl_secprops },
   # endif
       { "krb5_ccname", CONF_STR, FALSE, -1, &ldap_conf.krb5_ccname },
   #endif /* HAVE_LDAP_SASL_INTERACTIVE_BIND_S */
     { NULL }      { NULL }
 };  };
   
 static void sudo_ldap_update_defaults __P((LDAP *));  struct sudo_nss sudo_nss_ldap = {
 static void sudo_ldap_close __P((LDAP *));      &sudo_nss_ldap,
 static LDAP *sudo_ldap_open __P((void));      NULL,
       sudo_ldap_open,
       sudo_ldap_close,
       sudo_ldap_parse,
       sudo_ldap_setdefs,
       sudo_ldap_lookup,
       sudo_ldap_display_cmnd,
       sudo_ldap_display_defaults,
       sudo_ldap_display_bound_defaults,
       sudo_ldap_display_privs
   };
   
   #ifdef HAVE_LDAP_CREATE
   /*
    * Rebuild the hosts list and include a specific port for each host.
    * ldap_create() does not take a default port parameter so we must
    * append one if we want something other than LDAP_PORT.
    */
   static void
   sudo_ldap_conf_add_ports()
   {
   
       char *host, *port, defport[13];
       char hostbuf[LINE_MAX * 2];
   
       hostbuf[0] = '\0';
       if (snprintf(defport, sizeof(defport), ":%d", ldap_conf.port) >= sizeof(defport))
           errorx(1, "sudo_ldap_conf_add_ports: port too large");
   
       for ((host = strtok(ldap_conf.host, " \t")); host; (host = strtok(NULL, " \t"))) {
           if (hostbuf[0] != '\0') {
               if (strlcat(hostbuf, " ", sizeof(hostbuf)) >= sizeof(hostbuf))
                   goto toobig;
           }
   
           if (strlcat(hostbuf, host, sizeof(hostbuf)) >= sizeof(hostbuf))
               goto toobig;
           /* Append port if there is not one already. */
           if ((port = strrchr(host, ':')) == NULL || !isdigit(port[1])) {
               if (strlcat(hostbuf, defport, sizeof(hostbuf)) >= sizeof(hostbuf))
                   goto toobig;
           }
       }
   
       free(ldap_conf.host);
       ldap_conf.host = estrdup(hostbuf);
       return;
   
   toobig:
       errorx(1, "sudo_ldap_conf_add_ports: out of space expanding hostbuf");
   }
   #endif
   
 #ifndef HAVE_LDAP_INITIALIZE  #ifndef HAVE_LDAP_INITIALIZE
 /*  /*
  * For each uri, convert to host:port pairs.  For ldaps:// enable SSL   * For each uri, convert to host:port pairs.  For ldaps:// enable SSL
Line 220 
Line 313 
             nldaps++;              nldaps++;
             host = uri + 8;              host = uri + 8;
         } else {          } else {
             warnx("unsupported LDAP uri type: %s", uri);              warningx("unsupported LDAP uri type: %s", uri);
             goto done;              goto done;
         }          }
   
Line 248 
Line 341 
         }          }
     }      }
     if (hostbuf[0] == '\0') {      if (hostbuf[0] == '\0') {
         warnx("invalid uri: %s", uri_list);          warningx("invalid uri: %s", uri_list);
         goto done;          goto done;
     }      }
   
     if (nldaps != 0) {      if (nldaps != 0) {
         if (nldap != 0) {          if (nldap != 0) {
             warnx("cannot mix ldap and ldaps URIs");              warningx("cannot mix ldap and ldaps URIs");
             goto done;              goto done;
         }          }
         if (ldap_conf.ssl_mode == SUDO_LDAP_STARTTLS) {          if (ldap_conf.ssl_mode == SUDO_LDAP_STARTTLS) {
             warnx("cannot mix ldaps and starttls");              warningx("cannot mix ldaps and starttls");
             goto done;              goto done;
         }          }
         ldap_conf.ssl_mode = SUDO_LDAP_SSL;          ldap_conf.ssl_mode = SUDO_LDAP_SSL;
Line 273 
Line 366 
     return(rc);      return(rc);
   
 toobig:  toobig:
     errx(1, "sudo_ldap_parse_uri: out of space building hostbuf");      errorx(1, "sudo_ldap_parse_uri: out of space building hostbuf");
 }  }
 #endif /* HAVE_LDAP_INITIALIZE */  #endif /* HAVE_LDAP_INITIALIZE */
   
Line 294 
Line 387 
         rc = ldapssl_clientauth_init(ldap_conf.tls_certfile, NULL,          rc = ldapssl_clientauth_init(ldap_conf.tls_certfile, NULL,
             ldap_conf.tls_keyfile != NULL, ldap_conf.tls_keyfile, NULL);              ldap_conf.tls_keyfile != NULL, ldap_conf.tls_keyfile, NULL);
         if (rc != LDAP_SUCCESS) {          if (rc != LDAP_SUCCESS) {
             warnx("unable to initialize SSL cert and key db: %s",              warningx("unable to initialize SSL cert and key db: %s",
                 ldapssl_err2string(rc));                  ldapssl_err2string(rc));
             goto done;              goto done;
         }          }
   
         DPRINTF(("ldapssl_init(%s, %d, 1)", host, port), 2);          DPRINTF(("ldapssl_init(%s, %d, 1)", host, port), 2);
         if ((ld = ldapssl_init(host, port, 1)) == NULL)          if ((ld = ldapssl_init(host, port, 1)) != NULL)
             goto done;              rc = LDAP_SUCCESS;
     } else      } else
 #endif  #endif
     {      {
         DPRINTF(("ldap_init(%s, %d)", host, port), 2);  #ifdef HAVE_LDAP_CREATE
         if ((ld = ldap_init(host, port)) == NULL)          DPRINTF(("ldap_create()"), 2);
           if ((rc = ldap_create(&ld)) != LDAP_SUCCESS)
             goto done;              goto done;
           DPRINTF(("ldap_set_option(LDAP_OPT_HOST_NAME, %s)", host), 2);
           rc = ldap_set_option(ld, LDAP_OPT_HOST_NAME, host);
   #else
           DPRINTF(("ldap_init(%s, %d)", host, port), 2);
           if ((ld = ldap_init(host, port)) != NULL)
               rc = LDAP_SUCCESS;
   #endif
     }      }
     rc = LDAP_SUCCESS;  
   
 done:  done:
     *ldp = ld;      *ldp = ld;
Line 321 
Line 421 
  * netgroup, else FALSE.   * netgroup, else FALSE.
  */   */
 int  int
 sudo_ldap_check_user_netgroup(ld, entry)  sudo_ldap_check_user_netgroup(ld, entry, user)
     LDAP *ld;      LDAP *ld;
     LDAPMessage *entry;      LDAPMessage *entry;
       char *user;
 {  {
     char **v = NULL, **p = NULL;      struct berval **bv, **p;
       char *val;
     int ret = FALSE;      int ret = FALSE;
   
     if (!entry)      if (!entry)
         return(ret);          return(ret);
   
     /* get the values from the entry */      /* get the values from the entry */
     v = ldap_get_values(ld, entry, "sudoUser");      bv = ldap_get_values_len(ld, entry, "sudoUser");
       if (bv == NULL)
           return(ret);
   
     /* walk through values */      /* walk through values */
     for (p = v; p && *p && !ret; p++) {      for (p = bv; *p != NULL && !ret; p++) {
           val = (*p)->bv_val;
         /* match any */          /* match any */
         if (netgr_matches(*p, NULL, NULL, user_name))          if (netgr_matches(val, NULL, NULL, user))
             ret = TRUE;              ret = TRUE;
         DPRINTF(("ldap sudoUser netgroup '%s' ... %s", *p,          DPRINTF(("ldap sudoUser netgroup '%s' ... %s", val,
             ret ? "MATCH!" : "not"), 2);              ret ? "MATCH!" : "not"), 2);
     }      }
   
     if (v)      ldap_value_free_len(bv);    /* cleanup */
         ldap_value_free(v);     /* cleanup */  
   
     return(ret);      return(ret);
 }  }
Line 358 
Line 462 
     LDAP *ld;      LDAP *ld;
     LDAPMessage *entry;      LDAPMessage *entry;
 {  {
     char **v = NULL, **p = NULL;      struct berval **bv, **p;
       char *val;
     int ret = FALSE;      int ret = FALSE;
   
     if (!entry)      if (!entry)
         return(ret);          return(ret);
   
     /* get the values from the entry */      /* get the values from the entry */
     v = ldap_get_values(ld, entry, "sudoHost");      bv = ldap_get_values_len(ld, entry, "sudoHost");
       if (bv == NULL)
           return(ret);
   
     /* walk through values */      /* walk through values */
     for (p = v; p && *p && !ret; p++) {      for (p = bv; *p != NULL && !ret; p++) {
           val = (*p)->bv_val;
         /* match any or address or netgroup or hostname */          /* match any or address or netgroup or hostname */
         if (!strcmp(*p, "ALL") || addr_matches(*p) ||          if (!strcmp(val, "ALL") || addr_matches(val) ||
             netgr_matches(*p, user_host, user_shost, NULL) ||              netgr_matches(val, user_host, user_shost, NULL) ||
             !hostname_matches(user_shost, user_host, *p))              hostname_matches(user_shost, user_host, val))
             ret = TRUE;              ret = TRUE;
         DPRINTF(("ldap sudoHost '%s' ... %s", *p,          DPRINTF(("ldap sudoHost '%s' ... %s", val,
             ret ? "MATCH!" : "not"), 2);              ret ? "MATCH!" : "not"), 2);
     }      }
   
     if (v)      ldap_value_free_len(bv);    /* cleanup */
         ldap_value_free(v);     /* cleanup */  
   
     return(ret);      return(ret);
 }  }
   
 /*  
  * Walk through search results and return TRUE if we have a runas match,  
  * else FALSE.  
  * Since the runas directive in /etc/sudoers is optional, so is sudoRunAs.  
  */  
 int  int
 sudo_ldap_check_runas(ld, entry)  sudo_ldap_check_runas_user(ld, entry)
     LDAP *ld;      LDAP *ld;
     LDAPMessage *entry;      LDAPMessage *entry;
 {  {
     char **v = NULL, **p = NULL;      struct berval **bv, **p;
       char *val;
     int ret = FALSE;      int ret = FALSE;
   
     if (!entry)      if (!runas_pw)
         return(ret);          return(UNSPEC);
   
     /* get the values from the entry */      /* get the runas user from the entry */
     v = ldap_get_values(ld, entry, "sudoRunAs");      bv = ldap_get_values_len(ld, entry, "sudoRunAsUser");
       if (bv == NULL)
           bv = ldap_get_values_len(ld, entry, "sudoRunAs"); /* old style */
   
     /*      /*
      * BUG:       * BUG:
Line 416 
Line 521 
      * For now just require users to always use -u option unless its set       * For now just require users to always use -u option unless its set
      * in the global defaults. This behaviour is no different than the global       * in the global defaults. This behaviour is no different than the global
      * /etc/sudoers.       * /etc/sudoers.
      *       *
      * Sigh - maybe add this feature later       * Sigh - maybe add this feature later
      *  
      */       */
   
     /*      /*
      * If there are no runas entries, match runas_default against       * If there are no runas entries, match runas_default against
      * what the user specified on the command line.       * what the user specified on the command line.
      */       */
     if (!v)      if (bv == NULL)
         ret = !strcasecmp(runas_pw->pw_name, def_runas_default);          return(!strcasecmp(runas_pw->pw_name, def_runas_default));
   
     /* walk through values returned, looking for a match */      /* walk through values returned, looking for a match */
     for (p = v; p && *p && !ret; p++) {      for (p = bv; *p != NULL && !ret; p++) {
         switch (*p[0]) {          val = (*p)->bv_val;
           switch (val[0]) {
         case '+':          case '+':
             if (netgr_matches(*p, NULL, NULL, runas_pw->pw_name))              if (netgr_matches(val, NULL, NULL, runas_pw->pw_name))
                 ret = TRUE;                  ret = TRUE;
             break;              break;
         case '%':          case '%':
             if (usergr_matches(*p, runas_pw->pw_name, runas_pw))              if (usergr_matches(val, runas_pw->pw_name, runas_pw))
                 ret = TRUE;                  ret = TRUE;
             break;              break;
         case 'A':          case 'A':
             if (strcmp(*p, "ALL") == 0) {              if (strcmp(val, "ALL") == 0) {
                 ret = TRUE;                  ret = TRUE;
                 break;                  break;
             }              }
             /* FALLTHROUGH */              /* FALLTHROUGH */
         default:          default:
             if (strcasecmp(*p, runas_pw->pw_name) == 0)              if (strcasecmp(val, runas_pw->pw_name) == 0)
                 ret = TRUE;                  ret = TRUE;
             break;              break;
         }          }
         DPRINTF(("ldap sudoRunAs '%s' ... %s", *p,          DPRINTF(("ldap sudoRunAsUser '%s' ... %s", val,
             ret ? "MATCH!" : "not"), 2);              ret ? "MATCH!" : "not"), 2);
     }      }
   
     if (v)      ldap_value_free_len(bv);    /* cleanup */
         ldap_value_free(v);     /* cleanup */  
   
     return(ret);      return(ret);
 }  }
   
   int
   sudo_ldap_check_runas_group(ld, entry)
       LDAP *ld;
       LDAPMessage *entry;
   {
       struct berval **bv, **p;
       char *val;
       int ret = FALSE;
   
       /* runas_gr is only set if the user specified the -g flag */
       if (!runas_gr)
           return(UNSPEC);
   
       /* get the values from the entry */
       bv = ldap_get_values_len(ld, entry, "sudoRunAsGroup");
       if (bv == NULL)
           return(ret);
   
       /* walk through values returned, looking for a match */
       for (p = bv; *p != NULL && !ret; p++) {
           val = (*p)->bv_val;
           if (strcmp(val, "ALL") == 0 || group_matches(val, runas_gr))
               ret = TRUE;
           DPRINTF(("ldap sudoRunAsGroup '%s' ... %s", val,
               ret ? "MATCH!" : "not"), 2);
       }
   
       ldap_value_free_len(bv);    /* cleanup */
   
       return(ret);
   }
   
 /*  /*
  * Walk through search results and return TRUE if we have a command match.   * Walk through search results and return TRUE if we have a runas match,
    * else FALSE.  RunAs info is optional.
  */   */
 int  int
   sudo_ldap_check_runas(ld, entry)
       LDAP *ld;
       LDAPMessage *entry;
   {
       int ret;
   
       if (!entry)
           return(FALSE);
   
       ret = sudo_ldap_check_runas_user(ld, entry) != FALSE &&
           sudo_ldap_check_runas_group(ld, entry) != FALSE;
   
       return(ret);
   }
   
   /*
    * Walk through search results and return TRUE if we have a command match,
    * FALSE if disallowed and UNSPEC if not matched.
    */
   int
 sudo_ldap_check_command(ld, entry, setenv_implied)  sudo_ldap_check_command(ld, entry, setenv_implied)
     LDAP *ld;      LDAP *ld;
     LDAPMessage *entry;      LDAPMessage *entry;
     int *setenv_implied;      int *setenv_implied;
 {  {
     char *allowed_cmnd, *allowed_args, **v = NULL, **p = NULL;      struct berval **bv, **p;
     int foundbang, ret = FALSE;      char *allowed_cmnd, *allowed_args, *val;
       int foundbang, ret = UNSPEC;
   
     if (!entry)      if (!entry)
         return(ret);          return(ret);
   
     v = ldap_get_values(ld, entry, "sudoCommand");      bv = ldap_get_values_len(ld, entry, "sudoCommand");
       if (bv == NULL)
           return(ret);
   
     /* get_first_entry */      for (p = bv; *p != NULL && ret != FALSE; p++) {
     for (p = v; p && *p && ret >= 0; p++) {          val = (*p)->bv_val;
         /* Match against ALL ? */          /* Match against ALL ? */
         if (!strcmp(*p, "ALL")) {          if (!strcmp(val, "ALL")) {
             ret = TRUE;              ret = TRUE;
             if (setenv_implied != NULL)              if (setenv_implied != NULL)
                 *setenv_implied = TRUE;                  *setenv_implied = TRUE;
             DPRINTF(("ldap sudoCommand '%s' ... MATCH!", *p), 2);              DPRINTF(("ldap sudoCommand '%s' ... MATCH!", val), 2);
             continue;              continue;
         }          }
   
         /* check for !command */          /* check for !command */
         if (**p == '!') {          if (*val == '!') {
             foundbang = TRUE;              foundbang = TRUE;
             allowed_cmnd = estrdup(1 + *p);     /* !command */              allowed_cmnd = estrdup(1 + val);    /* !command */
         } else {          } else {
             foundbang = FALSE;              foundbang = FALSE;
             allowed_cmnd = estrdup(*p);         /* command */              allowed_cmnd = estrdup(val);        /* command */
         }          }
   
         /* split optional args away from command */          /* split optional args away from command */
Line 508 
Line 668 
              * If allowed (no bang) set ret but keep on checking.               * If allowed (no bang) set ret but keep on checking.
              * If disallowed (bang), exit loop.               * If disallowed (bang), exit loop.
              */               */
             ret = foundbang ? -1 : TRUE;              ret = foundbang ? FALSE : TRUE;
         }          }
         DPRINTF(("ldap sudoCommand '%s' ... %s", *p,          DPRINTF(("ldap sudoCommand '%s' ... %s", val,
             ret == TRUE ? "MATCH!" : "not"), 2);              ret == TRUE ? "MATCH!" : "not"), 2);
   
         efree(allowed_cmnd);    /* cleanup */          efree(allowed_cmnd);    /* cleanup */
     }      }
   
     if (v)      ldap_value_free_len(bv);    /* more cleanup */
         ldap_value_free(v);     /* more cleanup */  
   
     /* return TRUE if we found at least one ALLOW and no DENY */      return(ret);
     return(ret > 0);  
 }  }
   
 /*  /*
    * Search for boolean "option" in sudoOption.
    * Returns TRUE if found and allowed, FALSE if negated, else UNSPEC.
    */
   int
   sudo_ldap_check_bool(ld, entry, option)
       LDAP *ld;
       LDAPMessage *entry;
       char *option;
   {
       struct berval **bv, **p;
       char ch, *var;
       int ret = UNSPEC;
   
       if (entry == NULL)
           return(UNSPEC);
   
       bv = ldap_get_values_len(ld, entry, "sudoOption");
       if (bv == NULL)
           return(ret);
   
       /* walk through options */
       for (p = bv; *p != NULL; p++) {
           var = (*p)->bv_val;;
           DPRINTF(("ldap sudoOption: '%s'", var), 2);
   
           if ((ch = *var) == '!')
               var++;
           if (strcmp(var, option) == 0)
               ret = (ch != '!');
       }
   
       ldap_value_free_len(bv);
   
       return(ret);
   }
   
   /*
  * Read sudoOption and modify the defaults as we go.  This is used once   * Read sudoOption and modify the defaults as we go.  This is used once
  * from the cn=defaults entry and also once when a final sudoRole is matched.   * from the cn=defaults entry and also once when a final sudoRole is matched.
  */   */
Line 532 
Line 727 
     LDAP *ld;      LDAP *ld;
     LDAPMessage *entry;      LDAPMessage *entry;
 {  {
     char op, *var, *val, **v = NULL, **p = NULL;      struct berval **bv, **p;
       char op, *var, *val;
   
     if (!entry)      if (entry == NULL)
         return;          return;
   
     v = ldap_get_values(ld, entry, "sudoOption");      bv = ldap_get_values_len(ld, entry, "sudoOption");
       if (bv == NULL)
           return;
   
     /* walk through options */      /* walk through options */
     for (p = v; p && *p; p++) {      for (p = bv; *p != NULL; p++) {
           var = estrdup((*p)->bv_val);
           DPRINTF(("ldap sudoOption: '%s'", var), 2);
   
         DPRINTF(("ldap sudoOption: '%s'", *p), 2);  
         var = estrdup(*p);  
   
         /* check for equals sign past first char */          /* check for equals sign past first char */
         val = strchr(var, '=');          val = strchr(var, '=');
         if (val > var) {          if (val > var) {
Line 568 
Line 765 
         efree(var);          efree(var);
     }      }
   
     if (v)      ldap_value_free_len(bv);
         ldap_value_free(v);  
 }  }
   
 /*  /*
  * Concatenate strings, dynamically growing them as necessary.  
  * Strings can be arbitrarily long and are allocated/reallocated on  
  * the fly.  Make sure to free them when you are done.  
  *  
  * Usage:  
  *  
  * char *s=NULL;  
  * size_t sz;  
  *  
  * ncat(&s,&sz,"This ");  
  * ncat(&s,&sz,"is ");  
  * ncat(&s,&sz,"an ");  
  * ncat(&s,&sz,"arbitrarily ");  
  * ncat(&s,&sz,"long ");  
  * ncat(&s,&sz,"string!");  
  *  
  * printf("String Value='%s', but has %d bytes allocated\n",s,sz);  
  *  
  */  
 void  
 ncat(s, sz, src)  
     char **s;  
     size_t *sz;  
     char *src;  
 {  
     size_t nsz;  
   
     /* handle initial alloc */  
     if (*s == NULL) {  
         *s = estrdup(src);  
         *sz = strlen(src) + 1;  
         return;  
     }  
     /* handle realloc */  
     nsz = strlen(*s) + strlen(src) + 1;  
     if (*sz < nsz)  
         *s = erealloc((void *) *s, *sz = nsz * 2);  
     strlcat(*s, src, *sz);  
 }  
   
 /*  
  * builds together a filter to check against ldap   * builds together a filter to check against ldap
  */   */
 char *  char *
 sudo_ldap_build_pass1()  sudo_ldap_build_pass1(pw)
       struct passwd *pw;
 {  {
     struct group *grp;      struct group *grp;
     size_t sz;      size_t sz;
     char *b = NULL;      char *buf;
     int i;      int i;
   
     /* global OR */      /* Start with (|(sudoUser=USERNAME)(sudoUser=ALL)) + NUL */
     ncat(&b, &sz, "(|");      sz = 29 + strlen(pw->pw_name);
   
     /* build filter sudoUser=user_name */      /* Add space for groups */
     ncat(&b, &sz, "(sudoUser=");      if ((grp = sudo_getgrgid(pw->pw_gid)) != NULL)
     ncat(&b, &sz, user_name);          sz += 12 + strlen(grp->gr_name);        /* primary group */
     ncat(&b, &sz, ")");      for (i = 0; i < user_ngroups; i++) {
           if (user_groups[i] == pw->pw_gid)
               continue;
           if ((grp = sudo_getgrgid(user_groups[i])) != NULL)
               sz += 12 + strlen(grp->gr_name);    /* supplementary group */
       }
       buf = emalloc(sz);
   
       /* Global OR + sudoUser=user_name filter */
       (void) strlcpy(buf, "(|(sudoUser=", sz);
       (void) strlcat(buf, pw->pw_name, sz);
       (void) strlcat(buf, ")", sz);
   
     /* Append primary group */      /* Append primary group */
     grp = getgrgid(user_gid);      if ((grp = sudo_getgrgid(pw->pw_gid)) != NULL) {
     if (grp != NULL) {          (void) strlcat(buf, "(sudoUser=%", sz);
         ncat(&b, &sz, "(sudoUser=%");          (void) strlcat(buf, grp->gr_name, sz);
         ncat(&b, &sz, grp -> gr_name);          (void) strlcat(buf, ")", sz);
         ncat(&b, &sz, ")");  
     }      }
   
     /* Append supplementary groups */      /* Append supplementary groups */
     for (i = 0; i < user_ngroups; i++) {      for (i = 0; i < user_ngroups; i++) {
         if (user_groups[i] == user_gid)          if (user_groups[i] == pw->pw_gid)
             continue;              continue;
         if ((grp = getgrgid(user_groups[i])) != NULL) {          if ((grp = sudo_getgrgid(user_groups[i])) != NULL) {
             ncat(&b, &sz, "(sudoUser=%");              (void) strlcat(buf, "(sudoUser=%", sz);
             ncat(&b, &sz, grp -> gr_name);              (void) strlcat(buf, grp->gr_name, sz);
             ncat(&b, &sz, ")");              (void) strlcat(buf, ")", sz);
         }          }
     }      }
   
     /* Add ALL to list */      /* Add ALL to list and end the global OR */
     ncat(&b, &sz, "(sudoUser=ALL)");      if (strlcat(buf, "(sudoUser=ALL))", sz) >= sz)
           errorx(1, "sudo_ldap_build_pass1 allocation mismatch");
   
     /* End of OR List */      return(buf);
     ncat(&b, &sz, ")");  
   
     return(b);  
 }  }
   
 /*  /*
Line 699 
Line 863 
     return(-1);      return(-1);
 }  }
   
   static void
   sudo_ldap_read_secret(path)
       const char *path;
   {
       FILE *fp;
       char buf[LINE_MAX], *cp;
   
       if ((fp = fopen(_PATH_LDAP_SECRET, "r")) != NULL) {
           if (fgets(buf, sizeof(buf), fp) != NULL) {
               if ((cp = strchr(buf, '\n')) != NULL)
                   *cp = '\0';
               /* copy to bindpw and binddn */
               efree(ldap_conf.bindpw);
               ldap_conf.bindpw = estrdup(buf);
               efree(ldap_conf.binddn);
               ldap_conf.binddn = ldap_conf.rootbinddn;
               ldap_conf.rootbinddn = NULL;
           }
           fclose(fp);
       }
   }
   
 int  int
 sudo_ldap_read_config()  sudo_ldap_read_config()
 {  {
     FILE *f;      FILE *fp;
     char buf[LINE_MAX], *c, *keyword, *value;      char *cp, *keyword, *value;
     struct ldap_config_table *cur;      struct ldap_config_table *cur;
   
     /* defaults */      /* defaults */
Line 712 
Line 898 
     ldap_conf.tls_checkpeer = -1;      ldap_conf.tls_checkpeer = -1;
     ldap_conf.timelimit = -1;      ldap_conf.timelimit = -1;
     ldap_conf.bind_timelimit = -1;      ldap_conf.bind_timelimit = -1;
       ldap_conf.use_sasl = -1;
       ldap_conf.rootuse_sasl = -1;
   
     if ((f = fopen(_PATH_LDAP_CONF, "r")) == NULL)      if ((fp = fopen(_PATH_LDAP_CONF, "r")) == NULL)
         return(FALSE);          return(FALSE);
   
     while (fgets(buf, sizeof(buf), f)) {      while ((cp = sudo_parseln(fp)) != NULL) {
         /* ignore text after comment character */          if (*cp == '\0')
         if ((c = strchr(buf, '#')) != NULL)  
             *c = '\0';  
   
         /* skip leading whitespace */  
         for (c = buf; isspace((unsigned char) *c); c++)  
             /* nothing */;  
   
         if (*c == '\0' || *c == '\n')  
             continue;           /* skip empty line */              continue;           /* skip empty line */
   
         /* properly terminate keyword string */          /* split into keyword and value */
         keyword = c;          keyword = cp;
         while (*c && !isspace((unsigned char) *c))          while (*cp && !isblank((unsigned char) *cp))
             c++;              cp++;
         if (*c)          if (*cp)
             *c++ = '\0';        /* terminate keyword */              *cp++ = '\0';       /* terminate keyword */
   
         /* skip whitespace before value */          /* skip whitespace before value */
         while (isspace((unsigned char) *c))          while (isblank((unsigned char) *cp))
             c++;              cp++;
         value = c;          value = cp;
   
         /* trim whitespace after value */  
         while (*c)  
             c++;                /* wind to end */  
         while (--c > value && isspace((unsigned char) *c))  
             *c = '\0';  
   
         /* Look up keyword in config table. */          /* Look up keyword in config table. */
         for (cur = ldap_conf_table; cur->conf_str != NULL; cur++) {          for (cur = ldap_conf_table; cur->conf_str != NULL; cur++) {
             if (strcasecmp(keyword, cur->conf_str) == 0) {              if (strcasecmp(keyword, cur->conf_str) == 0) {
Line 765 
Line 939 
             }              }
         }          }
     }      }
     fclose(f);      fclose(fp);
   
     if (!ldap_conf.host)      if (!ldap_conf.host)
         ldap_conf.host = "localhost";          ldap_conf.host = estrdup("localhost");
   
     if (ldap_conf.bind_timelimit > 0)      if (ldap_conf.bind_timelimit > 0)
         ldap_conf.bind_timelimit *= 1000;       /* convert to ms */          ldap_conf.bind_timelimit *= 1000;       /* convert to ms */
Line 777 
Line 951 
         fprintf(stderr, "LDAP Config Summary\n");          fprintf(stderr, "LDAP Config Summary\n");
         fprintf(stderr, "===================\n");          fprintf(stderr, "===================\n");
         if (ldap_conf.uri) {          if (ldap_conf.uri) {
             fprintf(stderr, "uri          %s\n", ldap_conf.uri);              fprintf(stderr, "uri              %s\n", ldap_conf.uri);
         } else {          } else {
             fprintf(stderr, "host         %s\n", ldap_conf.host ?              fprintf(stderr, "host             %s\n", ldap_conf.host ?
                 ldap_conf.host : "(NONE)");                  ldap_conf.host : "(NONE)");
             fprintf(stderr, "port         %d\n", ldap_conf.port);              fprintf(stderr, "port             %d\n", ldap_conf.port);
         }          }
         fprintf(stderr, "ldap_version %d\n", ldap_conf.version);          fprintf(stderr, "ldap_version     %d\n", ldap_conf.version);
   
         fprintf(stderr, "sudoers_base %s\n", ldap_conf.base ?          fprintf(stderr, "sudoers_base     %s\n", ldap_conf.base ?
             ldap_conf.base : "(NONE) <---Sudo will ignore ldap)");              ldap_conf.base : "(NONE) <---Sudo will ignore ldap)");
         fprintf(stderr, "binddn       %s\n", ldap_conf.binddn ?          fprintf(stderr, "binddn           %s\n", ldap_conf.binddn ?
             ldap_conf.binddn : "(anonymous)");              ldap_conf.binddn : "(anonymous)");
         fprintf(stderr, "bindpw       %s\n", ldap_conf.bindpw ?          fprintf(stderr, "bindpw           %s\n", ldap_conf.bindpw ?
             ldap_conf.bindpw : "(anonymous)");              ldap_conf.bindpw : "(anonymous)");
         if (ldap_conf.bind_timelimit > 0)          if (ldap_conf.bind_timelimit > 0)
             fprintf(stderr, "bind_timelimit  %d\n", ldap_conf.bind_timelimit);              fprintf(stderr, "bind_timelimit   %d\n", ldap_conf.bind_timelimit);
         if (ldap_conf.timelimit > 0)          if (ldap_conf.timelimit > 0)
             fprintf(stderr, "timelimit    %d\n", ldap_conf.timelimit);              fprintf(stderr, "timelimit        %d\n", ldap_conf.timelimit);
         fprintf(stderr, "ssl          %s\n", ldap_conf.ssl ?          fprintf(stderr, "ssl              %s\n", ldap_conf.ssl ?
             ldap_conf.ssl : "(no)");              ldap_conf.ssl : "(no)");
         if (ldap_conf.tls_checkpeer != -1)          if (ldap_conf.tls_checkpeer != -1)
             fprintf(stderr, "tls_checkpeer    %s\n", ldap_conf.tls_checkpeer ?              fprintf(stderr, "tls_checkpeer    %s\n", ldap_conf.tls_checkpeer ?
Line 812 
Line 986 
             fprintf(stderr, "tls_certfile     %s\n", ldap_conf.tls_certfile);              fprintf(stderr, "tls_certfile     %s\n", ldap_conf.tls_certfile);
         if (ldap_conf.tls_keyfile != NULL)          if (ldap_conf.tls_keyfile != NULL)
             fprintf(stderr, "tls_keyfile      %s\n", ldap_conf.tls_keyfile);              fprintf(stderr, "tls_keyfile      %s\n", ldap_conf.tls_keyfile);
   #ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S
           if (ldap_conf.use_sasl != -1) {
               fprintf(stderr, "use_sasl         %s\n",
                   ldap_conf.use_sasl ? "yes" : "no");
               fprintf(stderr, "sasl_auth_id     %s\n", ldap_conf.sasl_auth_id ?
                   ldap_conf.sasl_auth_id : "(NONE)");
               fprintf(stderr, "rootuse_sasl     %d\n", ldap_conf.rootuse_sasl);
               fprintf(stderr, "rootsasl_auth_id %s\n", ldap_conf.rootsasl_auth_id ?
                   ldap_conf.rootsasl_auth_id : "(NONE)");
               fprintf(stderr, "sasl_secprops    %s\n", ldap_conf.sasl_secprops ?
                   ldap_conf.sasl_secprops : "(NONE)");
               fprintf(stderr, "krb5_ccname      %s\n", ldap_conf.krb5_ccname ?
                   ldap_conf.krb5_ccname : "(NONE)");
           }
   #endif
         fprintf(stderr, "===================\n");          fprintf(stderr, "===================\n");
     }      }
     if (!ldap_conf.base)      if (!ldap_conf.base)
Line 845 
Line 1034 
     }      }
 #endif  #endif
   
     /* Use port 389 for plaintext LDAP and port 636 for SSL LDAP */      if (!ldap_conf.uri) {
     if (!ldap_conf.uri && ldap_conf.port < 0)          /* Use port 389 for plaintext LDAP and port 636 for SSL LDAP */
         ldap_conf.port =          if (ldap_conf.port < 0)
             ldap_conf.ssl_mode == SUDO_LDAP_SSL ? LDAPS_PORT : LDAP_PORT;              ldap_conf.port =
                   ldap_conf.ssl_mode == SUDO_LDAP_SSL ? LDAPS_PORT : LDAP_PORT;
   
   #ifdef HAVE_LDAP_CREATE
           /*
            * Cannot specify port directly to ldap_create(), each host must
            * include :port to override the default.
            */
           if (ldap_conf.port != LDAP_PORT)
               sudo_ldap_conf_add_ports();
   #endif
       }
   
     /* If rootbinddn set, read in /etc/ldap.secret if it exists. */      /* If rootbinddn set, read in /etc/ldap.secret if it exists. */
     if (ldap_conf.rootbinddn) {      if (ldap_conf.rootbinddn)
         if ((f = fopen(_PATH_LDAP_SECRET, "r")) != NULL) {          sudo_ldap_read_secret(_PATH_LDAP_SECRET);
             if (fgets(buf, sizeof(buf), f) != NULL) {  
                 /* removing trailing newlines */  #ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S
                 for (c = buf; *c != '\0'; c++)      /*
                     continue;       * Make sure we can open the file specified by krb5_ccname.
                 while (--c > buf && *c == '\n')       */
                     *c = '\0';      if (ldap_conf.krb5_ccname != NULL) {
                 /* copy to bindpw and binddn */          if (strncasecmp(ldap_conf.krb5_ccname, "FILE:", 5) == 0 ||
                 efree(ldap_conf.bindpw);              strncasecmp(ldap_conf.krb5_ccname, "WRFILE:", 7) == 0) {
                 ldap_conf.bindpw = estrdup(buf);              value = ldap_conf.krb5_ccname +
                 efree(ldap_conf.binddn);                  (ldap_conf.krb5_ccname[4] == ':' ? 5 : 7);
                 ldap_conf.binddn = ldap_conf.rootbinddn;              if ((fp = fopen(value, "r")) != NULL) {
                 ldap_conf.rootbinddn = NULL;                  DPRINTF(("using krb5 credential cache: %s", value), 1);
                   fclose(fp);
               } else {
                   /* Can't open it, just ignore the entry. */
                   DPRINTF(("unable to open krb5 credential cache: %s", value), 1);
                   efree(ldap_conf.krb5_ccname);
                   ldap_conf.krb5_ccname = NULL;
             }              }
             fclose(f);  
         }          }
     }      }
   #endif
     return(TRUE);      return(TRUE);
 }  }
   
 /*  /*
  * like perl's join(sep,@ARGS)   * Extract the dn from an entry and return the first rdn from it.
  */   */
 char *  static char *
  _ldap_join_values(sep, v)  sudo_ldap_get_first_rdn(ld, entry)
     char *sep;      LDAP *ld;
     char **v;      LDAPMessage *entry;
 {  {
     char *b = NULL, **p = NULL;  #ifdef HAVE_LDAP_STR2DN
     size_t sz = 0;      char *dn, *rdn = NULL;
       LDAPDN tmpDN;
   
     /* paste values together */      if ((dn = ldap_get_dn(ld, entry)) == NULL)
     for (p = v; p && *p; p++) {          return(NULL);
         if (p != v && sep != NULL)      if (ldap_str2dn(dn, &tmpDN, LDAP_DN_FORMAT_LDAP) == LDAP_SUCCESS) {
             ncat(&b, &sz, sep); /* append separator */          ldap_rdn2str(tmpDN[0], &rdn, LDAP_DN_FORMAT_UFN);
         ncat(&b, &sz, *p);      /* append value */          ldap_dnfree(tmpDN);
     }      }
       ldap_memfree(dn);
       return(rdn);
   #else
       char *dn, **edn;
   
     /* sanity check */      if ((dn = ldap_get_dn(ld, entry)) == NULL)
     if (b[0] == '\0') {          return(NULL);
         /* something went wrong, put something here */      edn = ldap_explode_dn(dn, 1);
         ncat(&b, &sz, "(empty list)");  /* append value */      ldap_memfree(dn);
       return(edn ? edn[0] : NULL);
   #endif
   }
   
   /*
    * Fetch and display the global Options.
    */
   int
   sudo_ldap_display_defaults(nss, pw, lbuf)
       struct sudo_nss *nss;
       struct passwd *pw;
       struct lbuf *lbuf;
   {
       struct berval **bv, **p;
       LDAP *ld = (LDAP *) nss->handle;
       LDAPMessage *entry = NULL, *result = NULL;
       char *prefix = NULL;
       int rc, count = 0;
   
       if (ld == NULL)
           return(-1);
   
       rc = ldap_search_ext_s(ld, ldap_conf.base, LDAP_SCOPE_SUBTREE,
           "cn=defaults", NULL, 0, NULL, NULL, NULL, -1, &result);
       if (rc == LDAP_SUCCESS && (entry = ldap_first_entry(ld, result))) {
           bv = ldap_get_values_len(ld, entry, "sudoOption");
           if (bv != NULL) {
               if (lbuf->len == 0)
                   prefix = "    ";
               else
                   prefix = ", ";
               for (p = bv; *p != NULL; p++) {
                   lbuf_append(lbuf, prefix, (*p)->bv_val, NULL);
                   prefix = ", ";
                   count++;
               }
               ldap_value_free_len(bv);
           }
     }      }
       if (result)
           ldap_msgfree(result);
       return(count);
   }
   
     return(b);  /*
    * STUB
    */
   int
   sudo_ldap_display_bound_defaults(nss, pw, lbuf)
       struct sudo_nss *nss;
       struct passwd *pw;
       struct lbuf *lbuf;
   {
       return(1);
 }  }
   
 char *sudo_ldap_cm_list = NULL;  /*
 size_t sudo_ldap_cm_list_size;   * Print a record in the short form, ala file sudoers.
    */
   int
   sudo_ldap_display_entry_short(ld, entry, lbuf)
       LDAP *ld;
       LDAPMessage *entry;
       struct lbuf *lbuf;
   {
       struct berval **bv, **p;
       int count = 0;
   
 #define SAVE_LIST(x) ncat(&sudo_ldap_cm_list,&sudo_ldap_cm_list_size,(x))      lbuf_append(lbuf, "    (", NULL);
   
       /* get the RunAsUser Values from the entry */
       bv = ldap_get_values_len(ld, entry, "sudoRunAsUser");
       if (bv == NULL)
           bv = ldap_get_values_len(ld, entry, "sudoRunAs");
       if (bv != NULL) {
           for (p = bv; *p != NULL; p++) {
               if (p != bv)
                   lbuf_append(lbuf, ", ", NULL);
               lbuf_append(lbuf, (*p)->bv_val, NULL);
           }
           ldap_value_free_len(bv);
       } else
           lbuf_append(lbuf, def_runas_default, NULL);
   
       /* get the RunAsGroup Values from the entry */
       bv = ldap_get_values_len(ld, entry, "sudoRunAsGroup");
       if (bv != NULL) {
           lbuf_append(lbuf, " : ", NULL);
           for (p = bv; *p != NULL; p++) {
               if (p != bv)
                   lbuf_append(lbuf, ", ", NULL);
               lbuf_append(lbuf, (*p)->bv_val, NULL);
           }
           ldap_value_free_len(bv);
       }
       lbuf_append(lbuf, ") ", NULL);
   
       /* get the Option Values from the entry */
       bv = ldap_get_values_len(ld, entry, "sudoOption");
       if (bv != NULL) {
           char *cp, *tag;
   
           for (p = bv; *p != NULL; p++) {
               cp = (*p)->bv_val;
               if (*cp == '!')
                   cp++;
               tag = NULL;
               if (strcmp(cp, "authenticate") == 0)
                   tag = (*p)->bv_val[0] == '!' ?
                       "NOPASSWD: " : "PASSWD: ";
               else if (strcmp(cp, "noexec") == 0)
                   tag = (*p)->bv_val[0] == '!' ?
                       "EXEC: " : "NOEXEC: ";
               else if (strcmp(cp, "setenv") == 0)
                   tag = (*p)->bv_val[0] == '!' ?
                       "NOSETENV: " : "SETENV: ";
               if (tag != NULL)
                   lbuf_append(lbuf, tag, NULL);
               /* XXX - ignores other options */
           }
           ldap_value_free_len(bv);
       }
   
       /* get the Command Values from the entry */
       bv = ldap_get_values_len(ld, entry, "sudoCommand");
       if (bv != NULL) {
           for (p = bv; *p != NULL; p++) {
               if (p != bv)
                   lbuf_append(lbuf, ", ", NULL);
               lbuf_append(lbuf, (*p)->bv_val, NULL);
               count++;
           }
           ldap_value_free_len(bv);
       }
   
       lbuf_print(lbuf);           /* forces a newline */
       return(count);
   }
   
 /*  /*
  * Walks through search result and returns TRUE if we have a   * Print a record in the long form.
  * command match  
  */   */
 int  int
 sudo_ldap_add_match(ld, entry, pwflag)  sudo_ldap_display_entry_long(ld, entry, lbuf)
     LDAP *ld;      LDAP *ld;
     LDAPMessage *entry;      LDAPMessage *entry;
     int pwflag;      struct lbuf *lbuf;
 {  {
     char *dn, **edn, **v = NULL;      struct berval **bv, **p;
       char *rdn;
       int count = 0;
   
     /* if we are not collecting matches, then don't save them */      /* extract the dn, only show the first rdn */
     if (pwflag != I_LISTPW)      rdn = sudo_ldap_get_first_rdn(ld, entry);
         return(TRUE);      lbuf_print(lbuf);   /* force a newline */
       lbuf_append(lbuf, "LDAP Role: ", rdn ? rdn : "UNKNOWN", NULL);
       lbuf_print(lbuf);
       if (rdn)
           ldap_memfree(rdn);
   
     /* collect the dn, only show the rdn */      /* get the RunAsUser Values from the entry */
     dn = ldap_get_dn(ld, entry);      lbuf_append(lbuf, "    RunAsUsers: ", NULL);
     edn = dn ? ldap_explode_dn(dn, 1) : NULL;      bv = ldap_get_values_len(ld, entry, "sudoRunAsUser");
     SAVE_LIST("\nLDAP Role: ");      if (bv == NULL)
     SAVE_LIST((edn && *edn) ? *edn : "UNKNOWN");          bv = ldap_get_values_len(ld, entry, "sudoRunAs");
     SAVE_LIST("\n");      if (bv != NULL) {
     if (dn)          for (p = bv; *p != NULL; p++) {
         ldap_memfree(dn);              if (p != bv)
     if (edn)                  lbuf_append(lbuf, ", ", NULL);
         ldap_value_free(edn);              lbuf_append(lbuf, (*p)->bv_val, NULL);
           }
           ldap_value_free_len(bv);
       } else
           lbuf_append(lbuf, def_runas_default, NULL);
       lbuf_print(lbuf);
   
     /* get the Runas Values from the entry */      /* get the RunAsGroup Values from the entry */
     v = ldap_get_values(ld, entry, "sudoRunAs");      bv = ldap_get_values_len(ld, entry, "sudoRunAsGroup");
     if (v && *v) {      if (bv != NULL) {
         SAVE_LIST("  RunAs: (");          lbuf_append(lbuf, "    RunAsGroups: ", NULL);
         SAVE_LIST(_ldap_join_values(", ", v));          for (p = bv; *p != NULL; p++) {
         SAVE_LIST(")\n");              if (p != bv)
                   lbuf_append(lbuf, ", ", NULL);
               lbuf_append(lbuf, (*p)->bv_val, NULL);
           }
           ldap_value_free_len(bv);
           lbuf_print(lbuf);
     }      }
     if (v)  
         ldap_value_free(v);  
   
       /* get the Option Values from the entry */
       bv = ldap_get_values_len(ld, entry, "sudoOption");
       if (bv != NULL) {
           lbuf_append(lbuf, "    Options: ", NULL);
           for (p = bv; *p != NULL; p++) {
               if (p != bv)
                   lbuf_append(lbuf, ", ", NULL);
               lbuf_append(lbuf, (*p)->bv_val, NULL);
           }
           ldap_value_free_len(bv);
           lbuf_print(lbuf);
       }
   
     /* get the Command Values from the entry */      /* get the Command Values from the entry */
     v = ldap_get_values(ld, entry, "sudoCommand");      bv = ldap_get_values_len(ld, entry, "sudoCommand");
     if (v && *v) {      if (bv != NULL) {
         SAVE_LIST("  Commands:\n    ");          lbuf_append(lbuf, "    Commands:", NULL);
         SAVE_LIST(_ldap_join_values("\n    ", v));          lbuf_print(lbuf);
         SAVE_LIST("\n");          for (p = bv; *p != NULL; p++) {
     } else {              lbuf_append(lbuf, "\t", (*p)->bv_val, NULL);
         SAVE_LIST("  Commands: NONE\n");              lbuf_print(lbuf);
               count++;
           }
           ldap_value_free_len(bv);
     }      }
     if (v)  
         ldap_value_free(v);  
   
     return(FALSE);              /* Don't stop at the first match */      return(count);
 }  }
 #undef SAVE_LIST  
   
 void  /*
 sudo_ldap_list_matches()   * Like sudo_ldap_lookup(), except we just print entries.
    */
   int
   sudo_ldap_display_privs(nss, pw, lbuf)
       struct sudo_nss *nss;
       struct passwd *pw;
       struct lbuf *lbuf;
 {  {
     if (sudo_ldap_cm_list != NULL)      LDAP *ld = (LDAP *) nss->handle;
         printf("%s", sudo_ldap_cm_list);      LDAPMessage *entry = NULL, *result = NULL;
       char *filt;
       int rc, do_netgr, count = 0;
   
       if (ld == NULL)
           return(-1);
   
       /*
        * Okay - time to search for anything that matches this user
        * Lets limit it to only two queries of the LDAP server
        *
        * The first pass will look by the username, groups, and
        * the keyword ALL.  We will then inspect the results that
        * came back from the query.  We don't need to inspect the
        * sudoUser in this pass since the LDAP server already scanned
        * it for us.
        *
        * The second pass will return all the entries that contain
        * user netgroups.  Then we take the netgroups returned and
        * try to match them against the username.
        */
       for (do_netgr = 0; do_netgr < 2; do_netgr++) {
           filt = do_netgr ? estrdup("sudoUser=+*") : sudo_ldap_build_pass1(pw);
           DPRINTF(("ldap search '%s'", filt), 1);
           rc = ldap_search_ext_s(ld, ldap_conf.base, LDAP_SCOPE_SUBTREE, filt,
               NULL, 0, NULL, NULL, NULL, -1, &result);
           efree(filt);
           if (rc != LDAP_SUCCESS)
               continue;   /* no entries for this pass */
   
           /* print each matching entry */
           LDAP_FOREACH(entry, ld, result) {
               if ((!do_netgr ||
                   sudo_ldap_check_user_netgroup(ld, entry, pw->pw_name)) &&
                   sudo_ldap_check_host(ld, entry)) {
   
                   if (long_list)
                       count += sudo_ldap_display_entry_long(ld, entry, lbuf);
                   else
                       count += sudo_ldap_display_entry_short(ld, entry, lbuf);
               }
           }
           ldap_msgfree(result);
           result = NULL;
       }
       return(count);
 }  }
   
   int
   sudo_ldap_display_cmnd(nss, pw)
       struct sudo_nss *nss;
       struct passwd *pw;
   {
       LDAP *ld = (LDAP *) nss->handle;
       LDAPMessage *entry = NULL, *result = NULL;  /* used for searches */
       char *filt;                                 /* used to parse attributes */
       int rc, found, do_netgr;                    /* temp/final return values */
   
       if (ld == NULL)
           return(1);
   
       /*
        * Okay - time to search for anything that matches this user
        * Lets limit it to only two queries of the LDAP server
        *
        * The first pass will look by the username, groups, and
        * the keyword ALL.  We will then inspect the results that
        * came back from the query.  We don't need to inspect the
        * sudoUser in this pass since the LDAP server already scanned
        * it for us.
        *
        * The second pass will return all the entries that contain
        * user netgroups.  Then we take the netgroups returned and
        * try to match them against the username.
        */
       for (found = FALSE, do_netgr = 0; !found && do_netgr < 2; do_netgr++) {
           filt = do_netgr ? estrdup("sudoUser=+*") : sudo_ldap_build_pass1(pw);
           DPRINTF(("ldap search '%s'", filt), 1);
           rc = ldap_search_ext_s(ld, ldap_conf.base, LDAP_SCOPE_SUBTREE, filt,
               NULL, 0, NULL, NULL, NULL, -1, &result);
           efree(filt);
           if (rc != LDAP_SUCCESS)
               continue;   /* no entries for this pass */
   
           LDAP_FOREACH(entry, ld, result) {
               if ((!do_netgr ||
                   sudo_ldap_check_user_netgroup(ld, entry, pw->pw_name)) &&
                   sudo_ldap_check_host(ld, entry) &&
                   sudo_ldap_check_command(ld, entry, NULL) &&
                   sudo_ldap_check_runas(ld, entry)) {
   
                   found = TRUE;
                   break;
               }
           }
           ldap_msgfree(result);
           result = NULL;
       }
   
       if (found)
           printf("%s%s%s\n", safe_cmnd ? safe_cmnd : user_cmnd,
               user_args ? " " : "", user_args ? user_args : "");
      return(!found);
   }
   
   #ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S
   static int
   sudo_ldap_sasl_interact(ld, flags, _auth_id, _interact)
       LDAP *ld;
       unsigned int flags;
       void *_auth_id;
       void *_interact;
   {
       char *auth_id = (char *)_auth_id;
       sasl_interact_t *interact = (sasl_interact_t *)_interact;
   
       for (; interact->id != SASL_CB_LIST_END; interact++) {
           if (interact->id != SASL_CB_USER)
               return(LDAP_PARAM_ERROR);
   
           if (auth_id != NULL)
               interact->result = auth_id;
           else if (interact->defresult != NULL)
               interact->result = interact->defresult;
           else
               interact->result = "";
   
           interact->len = strlen(interact->result);
   #if SASL_VERSION_MAJOR < 2
           interact->result = estrdup(interact->result);
   #endif /* SASL_VERSION_MAJOR < 2 */
       }
       return(LDAP_SUCCESS);
   }
   #endif /* HAVE_LDAP_SASL_INTERACTIVE_BIND_S */
   
 /*  /*
  * Set LDAP options based on the config table.   * Set LDAP options based on the config table.
  */   */
Line 996 
Line 1502 
             if (ival >= 0) {              if (ival >= 0) {
                 rc = ldap_set_option(conn, cur->opt_val, &ival);                  rc = ldap_set_option(conn, cur->opt_val, &ival);
                 if (rc != LDAP_OPT_SUCCESS) {                  if (rc != LDAP_OPT_SUCCESS) {
                     warnx("ldap_set_option: %s -> %d: %s",                      warningx("ldap_set_option: %s -> %d: %s",
                         cur->conf_str, ival, ldap_err2string(rc));                          cur->conf_str, ival, ldap_err2string(rc));
                     return(-1);                      return(-1);
                 }                  }
Line 1008 
Line 1514 
             if (sval != NULL) {              if (sval != NULL) {
                 rc = ldap_set_option(conn, cur->opt_val, sval);                  rc = ldap_set_option(conn, cur->opt_val, sval);
                 if (rc != LDAP_OPT_SUCCESS) {                  if (rc != LDAP_OPT_SUCCESS) {
                     warnx("ldap_set_option: %s -> %s: %s",                      warningx("ldap_set_option: %s -> %s: %s",
                         cur->conf_str, sval, ldap_err2string(rc));                          cur->conf_str, sval, ldap_err2string(rc));
                     return(-1);                      return(-1);
                 }                  }
Line 1026 
Line 1532 
         tv.tv_usec = 0;          tv.tv_usec = 0;
         rc = ldap_set_option(ld, LDAP_OPT_NETWORK_TIMEOUT, &tv);          rc = ldap_set_option(ld, LDAP_OPT_NETWORK_TIMEOUT, &tv);
         if (rc != LDAP_OPT_SUCCESS) {          if (rc != LDAP_OPT_SUCCESS) {
             warnx("ldap_set_option(NETWORK_TIMEOUT, %ld): %s",              warningx("ldap_set_option(NETWORK_TIMEOUT, %ld): %s",
                 (long)tv.tv_sec, ldap_err2string(rc));                  (long)tv.tv_sec, ldap_err2string(rc));
             return(-1);              return(-1);
         }          }
Line 1040 
Line 1546 
         int val = LDAP_OPT_X_TLS_HARD;          int val = LDAP_OPT_X_TLS_HARD;
         rc = ldap_set_option(ld, LDAP_OPT_X_TLS, &val);          rc = ldap_set_option(ld, LDAP_OPT_X_TLS, &val);
         if (rc != LDAP_SUCCESS) {          if (rc != LDAP_SUCCESS) {
             warnx("ldap_set_option(LDAP_OPT_X_TLS, LDAP_OPT_X_TLS_HARD): %s",              warningx("ldap_set_option(LDAP_OPT_X_TLS, LDAP_OPT_X_TLS_HARD): %s",
                 ldap_err2string(rc));                  ldap_err2string(rc));
             return(-1);              return(-1);
         }          }
Line 1051 
Line 1557 
 }  }
   
 /*  /*
  * Open a connection to the LDAP server.   * Connect to the LDAP server specified by ld
  */   */
 static LDAP *  static int
 sudo_ldap_open()  sudo_ldap_bind_s(ld)
       LDAP *ld;
 {  {
     LDAP *ld = NULL;  
     int rc;      int rc;
       const char *old_ccname = user_ccname;
   #ifdef HAVE_GSS_KRB5_CCACHE_NAME
       unsigned int status;
   #endif
   
   #ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S
       if (ldap_conf.rootuse_sasl == TRUE ||
           (ldap_conf.rootuse_sasl != FALSE && ldap_conf.use_sasl == TRUE)) {
           void *auth_id = ldap_conf.rootsasl_auth_id ?
               ldap_conf.rootsasl_auth_id : ldap_conf.sasl_auth_id;
   
           if (ldap_conf.krb5_ccname != NULL) {
   #ifdef HAVE_GSS_KRB5_CCACHE_NAME
               if (gss_krb5_ccache_name(&status, ldap_conf.krb5_ccname, &old_ccname)
                   != GSS_S_COMPLETE) {
                   old_ccname = NULL;
                   DPRINTF(("gss_krb5_ccache_name() failed: %d", status), 1);
               }
   #else
               sudo_setenv("KRB5CCNAME", ldap_conf.krb5_ccname, TRUE);
   #endif
           }
           rc = ldap_sasl_interactive_bind_s(ld, ldap_conf.binddn, "GSSAPI",
               NULL, NULL, LDAP_SASL_QUIET, sudo_ldap_sasl_interact, auth_id);
           if (ldap_conf.krb5_ccname != NULL) {
   #ifdef HAVE_GSS_KRB5_CCACHE_NAME
               if (gss_krb5_ccache_name(&status, old_ccname, NULL) != GSS_S_COMPLETE)
                       DPRINTF(("gss_krb5_ccache_name() failed: %d", status), 1);
   #else
               if (old_ccname != NULL)
                   sudo_setenv("KRB5CCNAME", old_ccname, TRUE);
               else
                   sudo_unsetenv("KRB5CCNAME");
   #endif
           }
           if (rc != LDAP_SUCCESS) {
               warningx("ldap_sasl_interactive_bind_s(): %s", ldap_err2string(rc));
               return(-1);
           }
           DPRINTF(("ldap_sasl_interactive_bind_s() ok"), 1);
       } else
   #endif /* HAVE_LDAP_SASL_INTERACTIVE_BIND_S */
   #ifdef HAVE_LDAP_SASL_BIND_S
       {
           struct berval bv;
   
           bv.bv_val = ldap_conf.bindpw ? ldap_conf.bindpw : "";
           bv.bv_len = strlen(bv.bv_val);
   
           rc = ldap_sasl_bind_s(ld, ldap_conf.binddn, LDAP_SASL_SIMPLE, &bv,
               NULL, NULL, NULL);
           if (rc != LDAP_SUCCESS) {
               warningx("ldap_sasl_bind_s(): %s", ldap_err2string(rc));
               return(-1);
           }
           DPRINTF(("ldap_sasl_bind_s() ok"), 1);
       }
   #else
       {
           rc = ldap_simple_bind_s(ld, ldap_conf.binddn, ldap_conf.bindpw);
           if (rc != LDAP_SUCCESS) {
               warningx("ldap_simple_bind_s(): %s", ldap_err2string(rc));
               return(-1);
           }
           DPRINTF(("ldap_simple_bind_s() ok"), 1);
       }
   #endif
       return(0);
   }
   
   /*
    * Open a connection to the LDAP server.
    * Returns 0 on success and non-zero on failure.
    */
   int
   sudo_ldap_open(nss)
       struct sudo_nss *nss;
   {
       LDAP *ld;
       int rc, ldapnoinit = FALSE;
   
     if (!sudo_ldap_read_config())      if (!sudo_ldap_read_config())
         return(NULL);          return(-1);
   
       /* Prevent reading of user ldaprc and system defaults. */
       if (getenv("LDAPNOINIT") == NULL) {
           ldapnoinit = TRUE;
           sudo_setenv("LDAPNOINIT", "1", TRUE);
       }
   
     /* Connect to LDAP server */      /* Connect to LDAP server */
 #ifdef HAVE_LDAP_INITIALIZE  #ifdef HAVE_LDAP_INITIALIZE
     if (ldap_conf.uri != NULL) {      if (ldap_conf.uri != NULL) {
         DPRINTF(("ldap_initialize(ld, %s)", ldap_conf.uri), 2);          DPRINTF(("ldap_initialize(ld, %s)", ldap_conf.uri), 2);
         rc = ldap_initialize(&ld, ldap_conf.uri);          rc = ldap_initialize(&ld, ldap_conf.uri);
     } else      } else
 #endif /* HAVE_LDAP_INITIALIZE */  #endif
         rc = sudo_ldap_init(&ld, ldap_conf.host, ldap_conf.port);          rc = sudo_ldap_init(&ld, ldap_conf.host, ldap_conf.port);
     if (rc != LDAP_SUCCESS) {      if (rc != LDAP_SUCCESS) {
         warnx("unable to initialize LDAP: %s", ldap_err2string(rc));          warningx("unable to initialize LDAP: %s", ldap_err2string(rc));
         return(NULL);          return(-1);
     }      }
   
       if (ldapnoinit)
           sudo_unsetenv("LDAPNOINIT");
   
     /* Set LDAP options */      /* Set LDAP options */
     if (sudo_ldap_set_options(ld) < 0)      if (sudo_ldap_set_options(ld) < 0)
         return(NULL);          return(-1);
   
     if (ldap_conf.ssl_mode == SUDO_LDAP_STARTTLS) {      if (ldap_conf.ssl_mode == SUDO_LDAP_STARTTLS) {
 #ifdef HAVE_LDAP_START_TLS_S  #ifdef HAVE_LDAP_START_TLS_S
         rc = ldap_start_tls_s(ld, NULL, NULL);          rc = ldap_start_tls_s(ld, NULL, NULL);
         if (rc != LDAP_SUCCESS) {          if (rc != LDAP_SUCCESS) {
             warnx("ldap_start_tls_s(): %s", ldap_err2string(rc));              warningx("ldap_start_tls_s(): %s", ldap_err2string(rc));
             ldap_unbind(ld);              return(-1);
             return(NULL);  
         }          }
         DPRINTF(("ldap_start_tls_s() ok"), 1);          DPRINTF(("ldap_start_tls_s() ok"), 1);
 #else  #else
         warnx("start_tls specified but LDAP libs do not support ldap_start_tls_s()");          warningx("start_tls specified but LDAP libs do not support ldap_start_tls_s()");
 #endif /* HAVE_LDAP_START_TLS_S */  #endif /* HAVE_LDAP_START_TLS_S */
     }      }
   
     /* Actually connect */      /* Actually connect */
     if ((rc = ldap_simple_bind_s(ld, ldap_conf.binddn, ldap_conf.bindpw))) {      if (sudo_ldap_bind_s(ld) != 0)
         warnx("ldap_simple_bind_s: %s", ldap_err2string(rc));          return(-1);
         return(NULL);  
     }  
     DPRINTF(("ldap_simple_bind_s() ok"), 1);  
   
     return(ld);      nss->handle = ld;
       return(0);
 }  }
   
 static void  int
 sudo_ldap_update_defaults(ld)  sudo_ldap_setdefs(nss)
     LDAP *ld;      struct sudo_nss *nss;
 {  {
       LDAP *ld = (LDAP *) nss->handle;
     LDAPMessage *entry = NULL, *result = NULL;   /* used for searches */      LDAPMessage *entry = NULL, *result = NULL;   /* used for searches */
     int rc;                                      /* temp return value */      int rc;                                      /* temp return value */
   
     rc = ldap_search_s(ld, ldap_conf.base, LDAP_SCOPE_SUBTREE,      if (ld == NULL)
         "cn=defaults", NULL, 0, &result);          return(-1);
     if (rc == LDAP_SUCCESS && (entry = ldap_first_entry(ld, result))) {  
       rc = ldap_search_ext_s(ld, ldap_conf.base, LDAP_SCOPE_SUBTREE,
           "cn=defaults", NULL, 0, NULL, NULL, NULL, -1, &result);
       if (rc == 0 && (entry = ldap_first_entry(ld, result))) {
         DPRINTF(("found:%s", ldap_get_dn(ld, entry)), 1);          DPRINTF(("found:%s", ldap_get_dn(ld, entry)), 1);
         sudo_ldap_parse_options(ld, entry);          sudo_ldap_parse_options(ld, entry);
     } else      } else
Line 1120 
Line 1716 
   
     if (result)      if (result)
         ldap_msgfree(result);          ldap_msgfree(result);
   
       return(0);
 }  }
   
 /*  /*
  * like sudoers_lookup() - only LDAP style   * like sudoers_lookup() - only LDAP style
  */   */
 int  int
 sudo_ldap_check(pwflag)  sudo_ldap_lookup(nss, ret, pwflag)
       struct sudo_nss *nss;
       int ret;
     int pwflag;      int pwflag;
 {  {
     LDAP *ld;      LDAP *ld = (LDAP *) nss->handle;
     LDAPMessage *entry = NULL, *result = NULL;  /* used for searches */      LDAPMessage *entry = NULL, *result = NULL;
     char *filt;                                 /* used to parse attributes */      char *filt;
     int rc, ret = FALSE, do_netgr;              /* temp/final return values */      int do_netgr, rc, matched;
     int setenv_implied;      int setenv_implied;
     int ldap_user_matches = FALSE, ldap_host_matches = FALSE; /* flags */      int ldap_user_matches = FALSE, ldap_host_matches = FALSE;
       struct passwd *pw = list_pw ? list_pw : sudo_user.pw;
   
     /* Open a connection to the LDAP server. */      if (ld == NULL)
     if ((ld = sudo_ldap_open()) == NULL)          return(ret);
         return(VALIDATE_ERROR);  
   
     /* Parse Default options. */      if (pwflag) {
     sudo_ldap_update_defaults(ld);          int doauth = UNSPEC;
           enum def_tupple pwcheck =
               (pwflag == -1) ? never : sudo_defs_table[pwflag].sd_un.tuple;
   
           for (matched = 0, do_netgr = 0; !matched && do_netgr < 2; do_netgr++) {
               filt = do_netgr ? estrdup("sudoUser=+*") : sudo_ldap_build_pass1(pw);
               rc = ldap_search_ext_s(ld, ldap_conf.base, LDAP_SCOPE_SUBTREE, filt,
                   NULL, 0, NULL, NULL, NULL, -1, &result);
               efree(filt);
               if (rc != LDAP_SUCCESS)
                   continue;
   
               LDAP_FOREACH(entry, ld, result) {
                   /* only verify netgroup matches in pass 2 */
                   if (do_netgr && !sudo_ldap_check_user_netgroup(ld, entry, pw->pw_name))
                       continue;
   
                   ldap_user_matches = TRUE;
                   if (sudo_ldap_check_host(ld, entry)) {
                       ldap_host_matches = TRUE;
                       if ((pwcheck == any && doauth != FALSE) ||
                           (pwcheck == all && doauth == FALSE))
                           doauth = sudo_ldap_check_bool(ld, entry, "authenticate");
                       /* Only check the command when listing another user. */
                       if (user_uid == 0 || list_pw == NULL ||
                           user_uid == list_pw->pw_uid ||
                           sudo_ldap_check_command(ld, entry, NULL)) {
                           matched = 1;
                           break;  /* end foreach */
                       }
                   }
               }
               ldap_msgfree(result);
               result = NULL;
           }
           if (matched || user_uid == 0) {
               SET(ret, VALIDATE_OK);
               CLR(ret, VALIDATE_NOT_OK);
               if (def_authenticate) {
                   switch (pwcheck) {
                       case always:
                           SET(ret, FLAG_CHECK_USER);
                           break;
                       case all:
                       case any:
                           if (doauth == FALSE)
                               def_authenticate = FALSE;
                           break;
                       case never:
                           def_authenticate = FALSE;
                           break;
                       default:
                           break;
                   }
               }
           }
           goto done;
       }
   
     /*      /*
      * Okay - time to search for anything that matches this user       * Okay - time to search for anything that matches this user
      * Lets limit it to only two queries of the LDAP server       * Lets limit it to only two queries of the LDAP server
Line 1158 
Line 1815 
      * try to match them against the username.       * try to match them against the username.
      */       */
     setenv_implied = FALSE;      setenv_implied = FALSE;
     for (do_netgr = 0; !ret && do_netgr < 2; do_netgr++) {      for (matched = 0, do_netgr = 0; !matched && do_netgr < 2; do_netgr++) {
         filt = do_netgr ? estrdup("sudoUser=+*") : sudo_ldap_build_pass1();          filt = do_netgr ? estrdup("sudoUser=+*") : sudo_ldap_build_pass1(pw);
         DPRINTF(("ldap search '%s'", filt), 1);          DPRINTF(("ldap search '%s'", filt), 1);
         rc = ldap_search_s(ld, ldap_conf.base, LDAP_SCOPE_SUBTREE, filt,          rc = ldap_search_ext_s(ld, ldap_conf.base, LDAP_SCOPE_SUBTREE, filt,
             NULL, 0, &result);              NULL, 0, NULL, NULL, NULL, -1, &result);
         if (rc != LDAP_SUCCESS)          if (rc != LDAP_SUCCESS)
             DPRINTF(("nothing found for '%s'", filt), 1);              DPRINTF(("nothing found for '%s'", filt), 1);
         efree(filt);          efree(filt);
   
         /* parse each entry returned from this most recent search */          /* parse each entry returned from this most recent search */
         entry = rc ? NULL : ldap_first_entry(ld, result);          if (rc == LDAP_SUCCESS) {
         while (entry != NULL) {              LDAP_FOREACH(entry, ld, result) {
             DPRINTF(("found:%s", ldap_get_dn(ld, entry)), 1);                  DPRINTF(("found:%s", ldap_get_dn(ld, entry)), 1);
             if (                  if (
             /* first verify user netgroup matches - only if in pass 2 */                  /* first verify user netgroup matches - only if in pass 2 */
                 (!do_netgr || sudo_ldap_check_user_netgroup(ld, entry)) &&                      (!do_netgr || sudo_ldap_check_user_netgroup(ld, entry, pw->pw_name)) &&
             /* remember that user matched */                  /* remember that user matched */
                 (ldap_user_matches = -1) &&                      (ldap_user_matches = TRUE) &&
             /* verify host match */                  /* verify host match */
                 sudo_ldap_check_host(ld, entry) &&                      sudo_ldap_check_host(ld, entry) &&
             /* remember that host matched */                  /* remember that host matched */
                 (ldap_host_matches = -1) &&                      (ldap_host_matches = TRUE) &&
             /* add matches for listing later */                  /* verify runas match */
                 sudo_ldap_add_match(ld, entry, pwflag) &&                      sudo_ldap_check_runas(ld, entry) &&
             /* verify command match */                  /* verify command match */
                 sudo_ldap_check_command(ld, entry, &setenv_implied) &&                      (rc = sudo_ldap_check_command(ld, entry, &setenv_implied)) != UNSPEC
             /* verify runas match */                      ) {
                 sudo_ldap_check_runas(ld, entry)                      /* We have a match! */
                 ) {                      DPRINTF(("Command %sallowed", rc == TRUE ? "" : "NOT "), 1);
                 /* We have a match! */                      matched = TRUE;
                 DPRINTF(("Perfect Matched!"), 1);                      if (rc == TRUE) {
                 /* pick up any options */                          /* pick up any options */
                 if (setenv_implied)                          if (setenv_implied)
                     def_setenv = TRUE;                              def_setenv = TRUE;
                 sudo_ldap_parse_options(ld, entry);                          sudo_ldap_parse_options(ld, entry);
 #ifdef HAVE_SELINUX  #ifdef HAVE_SELINUX
                 /* Set role and type if not specified on command line. */                          /* Set role and type if not specified on command line. */
                 if (user_role == NULL)                          if (user_role == NULL)
                     user_role = def_role;                              user_role = def_role;
                 if (user_type == NULL)                          if (user_type == NULL)
                     user_type = def_type;                              user_type = def_type;
 #endif /* HAVE_SELINUX */  #endif /* HAVE_SELINUX */
                 /* make sure we don't reenter loop */                          /* make sure we don't reenter loop */
                 ret = VALIDATE_OK;                          SET(ret, VALIDATE_OK);
                 /* break from inside for loop */                          CLR(ret, VALIDATE_NOT_OK);
                 break;                      } else {
                           SET(ret, VALIDATE_NOT_OK);
                           CLR(ret, VALIDATE_OK);
                       }
                       /* break from inside for loop */
                       break;
                   }
             }              }
             entry = ldap_next_entry(ld, entry);  
         }  
         if (result)  
             ldap_msgfree(result);              ldap_msgfree(result);
         result = NULL;              result = NULL;
           }
     }      }
   
     sudo_ldap_close(ld);                /* shut down connection */  done:
   
     DPRINTF(("user_matches=%d", ldap_user_matches), 1);      DPRINTF(("user_matches=%d", ldap_user_matches), 1);
     DPRINTF(("host_matches=%d", ldap_host_matches), 1);      DPRINTF(("host_matches=%d", ldap_host_matches), 1);
   
     /* Check for special case for -v, -k, -l options */      if (!ISSET(ret, VALIDATE_OK)) {
     if (pwflag && ldap_user_matches && ldap_host_matches) {  
         /*  
          * Handle verifypw & listpw  
          *  
          * To be extra paranoid, since we haven't read any NOPASSWD options  
          * in /etc/sudoers yet, but we have to make the decission now, lets  
          * assume the worst and prefer to prompt for password unless the setting  
          * is "never". (example verifypw=never or listpw=never)  
          *  
          */  
         ret = VALIDATE_OK;  
         if (pwflag == -1) {  
             SET(ret, FLAG_NOPASS);              /* -k or -K */  
         } else {  
             switch (sudo_defs_table[pwflag].sd_un.tuple) {  
             case never:  
                 SET(ret, FLAG_NOPASS);  
                 break;  
             case always:  
                 if (def_authenticate)  
                     SET(ret, FLAG_CHECK_USER);  
                 break;  
             default:  
                 break;  
             }  
         }  
     }  
     if (ISSET(ret, VALIDATE_OK)) {  
         /* we have a match, should we check the password? */  
         if (!def_authenticate)  
             SET(ret, FLAG_NOPASS);  
         if (def_noexec)  
             SET(ret, FLAG_NOEXEC);  
         if (def_setenv)  
             SET(ret, FLAG_SETENV);  
     } else {  
         /* we do not have a match */          /* we do not have a match */
         ret = VALIDATE_NOT_OK;          if (pwflag && list_pw == NULL)
         if (pwflag)  
             SET(ret, FLAG_NO_CHECK);              SET(ret, FLAG_NO_CHECK);
         else if (!ldap_user_matches)  
             SET(ret, FLAG_NO_USER);  
         else if (!ldap_host_matches)  
             SET(ret, FLAG_NO_HOST);  
     }      }
     DPRINTF(("sudo_ldap_check(%d)=0x%02x", pwflag, ret), 1);      if (ldap_user_matches)
           CLR(ret, FLAG_NO_USER);
       if (ldap_host_matches)
           CLR(ret, FLAG_NO_HOST);
       DPRINTF(("sudo_ldap_lookup(%d)=0x%02x", pwflag, ret), 1);
   
     return(ret);      return(ret);
 }  }
Line 1271 
Line 1894 
 /*  /*
  * shut down LDAP connection   * shut down LDAP connection
  */   */
 static void  int
 sudo_ldap_close(LDAP *ld)  sudo_ldap_close(nss)
       struct sudo_nss *nss;
 {  {
     if (ld)      if (nss->handle != NULL) {
         ldap_unbind_s(ld);          ldap_unbind_ext_s((LDAP *) nss->handle, NULL, NULL);
           nss->handle = NULL;
       }
       return(0);
   }
   
   /*
    * STUB
    */
   int
   sudo_ldap_parse(nss)
       struct sudo_nss *nss;
   {
       return(0);
 }  }

Legend:
Removed from v.1.8  
changed lines
  Added in v.1.9