Diff for /embedaddon/sudo/plugins/sudoers/ldap.c between versions 1.1.1.4 and 1.1.1.5

version 1.1.1.4, 2013/07/22 10:46:12 version 1.1.1.5, 2013/10/14 07:56:34
Line 43 Line 43
 # include <time.h>  # include <time.h>
 #endif  #endif
 #include <ctype.h>  #include <ctype.h>
   #include <fcntl.h>
 #include <pwd.h>  #include <pwd.h>
 #include <grp.h>  #include <grp.h>
 #include <netinet/in.h>  #include <netinet/in.h>
Line 62 Line 63
 # else  # else
 #  include <sasl.h>  #  include <sasl.h>
 # endif  # endif
# if HAVE_GSS_KRB5_CCACHE_NAME# ifdef HAVE_DLOPEN
#  if defined(HAVE_GSSAPI_GSSAPI_KRB5_H)#  include <dlfcn.h>
#   include <gssapi/gssapi.h>else
#   include <gssapi/gssapi_krb5.h>#  include "compat/dlfcn.h"
#  elif defined(HAVE_GSSAPI_GSSAPI_H) 
#   include <gssapi/gssapi.h> 
#  else 
#   include <gssapi.h> 
#  endif 
 # endif  # endif
#endif#endif /* HAVE_LDAP_SASL_INTERACTIVE_BIND_S */
   
 #include "sudoers.h"  #include "sudoers.h"
 #include "parse.h"  #include "parse.h"
Line 603  sudo_ldap_init(LDAP **ldp, const char *host, int port) Line 599  sudo_ldap_init(LDAP **ldp, const char *host, int port)
     } else      } else
 #elif defined(HAVE_LDAP_SSL_INIT) && defined(HAVE_LDAP_SSL_CLIENT_INIT)  #elif defined(HAVE_LDAP_SSL_INIT) && defined(HAVE_LDAP_SSL_CLIENT_INIT)
     if (ldap_conf.ssl_mode == SUDO_LDAP_SSL) {      if (ldap_conf.ssl_mode == SUDO_LDAP_SSL) {
        if (ldap_ssl_client_init(ldap_conf.tls_keyfile, ldap_conf.tls_keypw, 0, &rc) != LDAP_SUCCESS) {        int sslrc;
            warningx("ldap_ssl_client_init(): %s", ldap_err2string(rc));        rc = ldap_ssl_client_init(ldap_conf.tls_keyfile, ldap_conf.tls_keypw,
             0, &sslrc);
         if (rc != LDAP_SUCCESS) {
             warningx("ldap_ssl_client_init(): %s (SSL reason code %d)",
                 ldap_err2string(rc), sslrc);
             debug_return_int(-1);              debug_return_int(-1);
         }          }
         DPRINTF2("ldap_ssl_init(%s, %d, NULL)", host, port);          DPRINTF2("ldap_ssl_init(%s, %d, NULL)", host, port);
Line 1441  sudo_ldap_parse_keyword(const char *keyword, const cha Line 1441  sudo_ldap_parse_keyword(const char *keyword, const cha
     debug_return_bool(false);      debug_return_bool(false);
 }  }
   
   #ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S
   static const char *
   sudo_krb5_ccname_path(const char *old_ccname)
   {
       const char *ccname = old_ccname;
       debug_decl(sudo_krb5_ccname_path, SUDO_DEBUG_LDAP)
   
       /* Strip off leading FILE: or WRFILE: prefix. */
       switch (ccname[0]) {
           case 'F':
           case 'f':
               if (strncasecmp(ccname, "FILE:", 5) == 0)
                   ccname += 5;
               break;
           case 'W':
           case 'w':
               if (strncasecmp(ccname, "WRFILE:", 7) == 0)
                   ccname += 7;
               break;
       }
       sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
           "ccache %s -> %s", old_ccname, ccname);
   
       /* Credential cache must be a fully-qualified path name. */
       debug_return_str(*ccname == '/' ? ccname : NULL);
   }
   
 static bool  static bool
   sudo_check_krb5_ccname(const char *ccname)
   {
       int fd = -1;
       const char *ccname_path;
       debug_decl(sudo_check_krb5_ccname, SUDO_DEBUG_LDAP)
   
       /* Strip off prefix to get path name. */
       ccname_path = sudo_krb5_ccname_path(ccname);
       if (ccname_path == NULL) {
           sudo_debug_printf(SUDO_DEBUG_WARN|SUDO_DEBUG_LINENO,
               "unsupported krb5 credential cache path: %s", ccname);
           debug_return_bool(false);
       }
       /* Make sure credential cache is fully-qualified and exists. */
       fd = open(ccname_path, O_RDONLY|O_NONBLOCK, 0);
       if (fd == -1) {
           sudo_debug_printf(SUDO_DEBUG_WARN|SUDO_DEBUG_LINENO,
               "unable to open krb5 credential cache: %s", ccname_path);
           debug_return_bool(false);
       }
       close(fd);
       sudo_debug_printf(SUDO_DEBUG_INFO,
           "using krb5 credential cache: %s", ccname_path);
       debug_return_bool(true);
   }
   #endif /* HAVE_LDAP_SASL_INTERACTIVE_BIND_S */
   
   static bool
 sudo_ldap_read_config(void)  sudo_ldap_read_config(void)
 {  {
     FILE *fp;      FILE *fp;
Line 1642  sudo_ldap_read_config(void) Line 1697  sudo_ldap_read_config(void)
      * Make sure we can open the file specified by krb5_ccname.       * Make sure we can open the file specified by krb5_ccname.
      */       */
     if (ldap_conf.krb5_ccname != NULL) {      if (ldap_conf.krb5_ccname != NULL) {
        if (strncasecmp(ldap_conf.krb5_ccname, "FILE:", 5) == 0 ||        if (!sudo_check_krb5_ccname(ldap_conf.krb5_ccname))
            strncasecmp(ldap_conf.krb5_ccname, "WRFILE:", 7) == 0) {            ldap_conf.krb5_ccname = NULL;
            value = ldap_conf.krb5_ccname + 
                (ldap_conf.krb5_ccname[4] == ':' ? 5 : 7); 
            if ((fp = fopen(value, "r")) != NULL) { 
                sudo_debug_printf(SUDO_DEBUG_INFO, 
                    "using krb5 credential cache: %s", value); 
                fclose(fp); 
            } else { 
                /* Can't open it, just ignore the entry. */ 
                sudo_debug_printf(SUDO_DEBUG_WARN|SUDO_DEBUG_LINENO, 
                    "unable to open krb5 credential cache: %s", value); 
                efree(ldap_conf.krb5_ccname); 
                ldap_conf.krb5_ccname = NULL; 
            } 
        } 
     }      }
 #endif  #endif
   
     debug_return_bool(true);      debug_return_bool(true);
 }  }
   
Line 1982  done: Line 2024  done:
 }  }
   
 #ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S  #ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S
   static unsigned int (*sudo_gss_krb5_ccache_name)(unsigned int *minor_status, const char *name, const char **old_name);
   
 static int  static int
   sudo_set_krb5_ccache_name(const char *name, const char **old_name)
   {
       int rc = 0;
       unsigned int junk;
       static bool initialized;
       debug_decl(sudo_set_krb5_ccache_name, SUDO_DEBUG_LDAP)
   
       if (!initialized) {
           sudo_gss_krb5_ccache_name = dlsym(RTLD_DEFAULT, "gss_krb5_ccache_name");
           initialized = true;
       }
   
       /*
        * Try to use gss_krb5_ccache_name() if possible.
        * We also need to set KRB5CCNAME since some LDAP libs may not use
        * gss_krb5_ccache_name().
        */
       if (sudo_gss_krb5_ccache_name != NULL) {
           rc = sudo_gss_krb5_ccache_name(&junk, name, old_name);
       } else {
           /* No gss_krb5_ccache_name(), fall back on KRB5CCNAME. */
           if (old_name != NULL)
               *old_name = sudo_getenv("KRB5CCNAME");
       }
       if (name != NULL && *name != '\0')
           sudo_setenv("KRB5CCNAME", name, true);
       else
           sudo_unsetenv("KRB5CCNAME");
   
       debug_return_int(rc);
   }
   
   /*
    * Make a copy of the credential cache file specified by KRB5CCNAME
    * which must be readable by the user.  The resulting cache file
    * is root-owned and will be removed after authenticating via SASL.
    */
   static char *
   sudo_krb5_copy_cc_file(const char *old_ccname)
   {
       int ofd, nfd;
       ssize_t nread, nwritten = -1;
       static char new_ccname[sizeof(_PATH_TMP) + sizeof("sudocc_XXXXXXXX") - 1];
       char buf[10240], *ret = NULL;
       debug_decl(sudo_krb5_copy_cc_file, SUDO_DEBUG_LDAP)
   
       old_ccname = sudo_krb5_ccname_path(old_ccname);
       if (old_ccname != NULL) {
           /* Open credential cache as user to prevent stolen creds. */
           set_perms(PERM_USER);
           ofd = open(old_ccname, O_RDONLY|O_NONBLOCK);
           restore_perms();
   
           if (ofd != -1) {
               (void) fcntl(ofd, F_SETFL, 0);
               if (lock_file(ofd, SUDO_LOCK)) {
                   snprintf(new_ccname, sizeof(new_ccname), "%s%s",
                       _PATH_TMP, "sudocc_XXXXXXXX");
                   nfd = mkstemp(new_ccname);
                   if (nfd != -1) {
                       sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
                           "copy ccache %s -> %s", old_ccname, new_ccname);
                       while ((nread = read(ofd, buf, sizeof(buf))) > 0) {
                           ssize_t off = 0;
                           do {
                               nwritten = write(nfd, buf + off, nread - off);
                               if (nwritten == -1) {
                                   warning("error writing to %s", new_ccname);
                                   goto write_error;
                               }
                               off += nwritten;
                           } while (off < nread);
                       }
                       if (nread == -1)
                           warning("unable to read %s", new_ccname);
   write_error:
                       close(nfd);
                       if (nread != -1 && nwritten != -1) {
                           ret = new_ccname;       /* success! */
                       } else {
                           unlink(new_ccname);     /* failed */
                       }
                   } else {
                       warning("unable to create temp file %s", new_ccname);
                   }
               }
               close(ofd);
           } else {
               sudo_debug_printf(SUDO_DEBUG_WARN|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
                   "unable to open %s", old_ccname);
           }
       }
       debug_return_str(ret);
   }
   
   static int
 sudo_ldap_sasl_interact(LDAP *ld, unsigned int flags, void *_auth_id,  sudo_ldap_sasl_interact(LDAP *ld, unsigned int flags, void *_auth_id,
     void *_interact)      void *_interact)
 {  {
     char *auth_id = (char *)_auth_id;      char *auth_id = (char *)_auth_id;
     sasl_interact_t *interact = (sasl_interact_t *)_interact;      sasl_interact_t *interact = (sasl_interact_t *)_interact;
       int rc = LDAP_SUCCESS;
     debug_decl(sudo_ldap_sasl_interact, SUDO_DEBUG_LDAP)      debug_decl(sudo_ldap_sasl_interact, SUDO_DEBUG_LDAP)
   
     for (; interact->id != SASL_CB_LIST_END; interact++) {      for (; interact->id != SASL_CB_LIST_END; interact++) {
        if (interact->id != SASL_CB_USER)        if (interact->id != SASL_CB_USER) {
            debug_return_int(LDAP_PARAM_ERROR);            warningx("sudo_ldap_sasl_interact: unexpected interact id %lu",
                 interact->id);
             rc = LDAP_PARAM_ERROR;
             break;
         }
   
         if (auth_id != NULL)          if (auth_id != NULL)
             interact->result = auth_id;              interact->result = auth_id;
Line 2003  sudo_ldap_sasl_interact(LDAP *ld, unsigned int flags,  Line 2148  sudo_ldap_sasl_interact(LDAP *ld, unsigned int flags, 
   
         interact->len = strlen(interact->result);          interact->len = strlen(interact->result);
 #if SASL_VERSION_MAJOR < 2  #if SASL_VERSION_MAJOR < 2
        interact->result = estrdup(interact->result);        interact->result = strdup(interact->result);
         if (interact->result == NULL) {
             rc = LDAP_NO_MEMORY;
             break;
         }
 #endif /* SASL_VERSION_MAJOR < 2 */  #endif /* SASL_VERSION_MAJOR < 2 */
           DPRINTF2("sudo_ldap_sasl_interact: SASL_CB_USER %s",
               (const char *)interact->result);
     }      }
    debug_return_int(LDAP_SUCCESS);    debug_return_int(rc);
 }  }
 #endif /* HAVE_LDAP_SASL_INTERACTIVE_BIND_S */  #endif /* HAVE_LDAP_SASL_INTERACTIVE_BIND_S */
   
   
 /*  /*
  * Set LDAP options from the specified options table   * Set LDAP options from the specified options table
  */   */
Line 2212  static int Line 2362  static int
 sudo_ldap_bind_s(LDAP *ld)  sudo_ldap_bind_s(LDAP *ld)
 {  {
     int rc;      int rc;
 #ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S  
     const char *old_ccname = user_ccname;  
 # ifdef HAVE_GSS_KRB5_CCACHE_NAME  
     unsigned int status;  
 # endif  
 #endif  
     debug_decl(sudo_ldap_bind_s, SUDO_DEBUG_LDAP)      debug_decl(sudo_ldap_bind_s, SUDO_DEBUG_LDAP)
   
 #ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S  #ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S
     if (ldap_conf.rootuse_sasl == true ||      if (ldap_conf.rootuse_sasl == true ||
         (ldap_conf.rootuse_sasl != false && ldap_conf.use_sasl == true)) {          (ldap_conf.rootuse_sasl != false && ldap_conf.use_sasl == true)) {
           const char *old_ccname = NULL;
           const char *new_ccname = ldap_conf.krb5_ccname;
           const char *tmp_ccname = NULL;
         void *auth_id = ldap_conf.rootsasl_auth_id ?          void *auth_id = ldap_conf.rootsasl_auth_id ?
             ldap_conf.rootsasl_auth_id : ldap_conf.sasl_auth_id;              ldap_conf.rootsasl_auth_id : ldap_conf.sasl_auth_id;
   
        if (ldap_conf.krb5_ccname != NULL) {        /* Make temp copy of the user's credential cache as needed. */
# ifdef HAVE_GSS_KRB5_CCACHE_NAME        if (ldap_conf.krb5_ccname == NULL && user_ccname != NULL) {
            if (gss_krb5_ccache_name(&status, ldap_conf.krb5_ccname, &old_ccname)            new_ccname = tmp_ccname = sudo_krb5_copy_cc_file(user_ccname);
                != GSS_S_COMPLETE) {            if (tmp_ccname == NULL) {
                old_ccname = NULL;                sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
                     "unable to copy user ccache %s", user_ccname);
             }
         }
 
         if (new_ccname != NULL) {
             rc = sudo_set_krb5_ccache_name(new_ccname, &old_ccname);
             if (rc == 0) {
                 sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
                     "set ccache name %s -> %s",
                     old_ccname ? old_ccname : "(none)", new_ccname);
             } else {
                 sudo_debug_printf(SUDO_DEBUG_WARN|SUDO_DEBUG_LINENO,                  sudo_debug_printf(SUDO_DEBUG_WARN|SUDO_DEBUG_LINENO,
                    "gss_krb5_ccache_name() failed: %d", status);                    "gss_krb5_ccache_name() failed: %d", rc);
             }              }
 # else  
             sudo_setenv("KRB5CCNAME", ldap_conf.krb5_ccname, true);  
 # endif  
         }          }
         rc = ldap_sasl_interactive_bind_s(ld, ldap_conf.binddn, "GSSAPI",          rc = ldap_sasl_interactive_bind_s(ld, ldap_conf.binddn, "GSSAPI",
             NULL, NULL, LDAP_SASL_QUIET, sudo_ldap_sasl_interact, auth_id);              NULL, NULL, LDAP_SASL_QUIET, sudo_ldap_sasl_interact, auth_id);
        if (ldap_conf.krb5_ccname != NULL) {        if (new_ccname != NULL) {
# ifdef HAVE_GSS_KRB5_CCACHE_NAME            rc = sudo_set_krb5_ccache_name(old_ccname, NULL);
            if (gss_krb5_ccache_name(&status, old_ccname, NULL) != GSS_S_COMPLETE)            if (rc == 0) {
                    sudo_debug_printf(SUDO_DEBUG_WARN|SUDO_DEBUG_LINENO,                sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
                        "gss_krb5_ccache_name() failed: %d", status);                    "restore ccache name %s -> %s", new_ccname, old_ccname);
# else            } else {
            if (old_ccname != NULL)                sudo_debug_printf(SUDO_DEBUG_WARN|SUDO_DEBUG_LINENO,
                sudo_setenv("KRB5CCNAME", old_ccname, true);                    "gss_krb5_ccache_name() failed: %d", rc);
            else            }
                sudo_unsetenv("KRB5CCNAME");            /* Remove temporary copy of user's credential cache. */
# endif            if (tmp_ccname != NULL)
                 unlink(tmp_ccname);
         }          }
         if (rc != LDAP_SUCCESS) {          if (rc != LDAP_SUCCESS) {
             warningx("ldap_sasl_interactive_bind_s(): %s",              warningx("ldap_sasl_interactive_bind_s(): %s",
Line 2345  sudo_ldap_open(struct sudo_nss *nss) Line 2501  sudo_ldap_open(struct sudo_nss *nss)
         }          }
         DPRINTF1("ldap_start_tls_s() ok");          DPRINTF1("ldap_start_tls_s() ok");
 #elif defined(HAVE_LDAP_SSL_CLIENT_INIT) && defined(HAVE_LDAP_START_TLS_S_NP)  #elif defined(HAVE_LDAP_SSL_CLIENT_INIT) && defined(HAVE_LDAP_START_TLS_S_NP)
        if (ldap_ssl_client_init(ldap_conf.tls_keyfile, ldap_conf.tls_keypw, 0, &rc) != LDAP_SUCCESS) {        int sslrc;
            warningx("ldap_ssl_client_init(): %s", ldap_err2string(rc));        rc = ldap_ssl_client_init(ldap_conf.tls_keyfile, ldap_conf.tls_keypw,
             0, &sslrc);
         if (rc != LDAP_SUCCESS) {
             warningx("ldap_ssl_client_init(): %s (SSL reason code %d)",
                 ldap_err2string(rc), sslrc);
             debug_return_int(-1);              debug_return_int(-1);
         }          }
         rc = ldap_start_tls_s_np(ld, NULL);          rc = ldap_start_tls_s_np(ld, NULL);

Removed from v.1.1.1.4  
changed lines
  Added in v.1.1.1.5


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>