Esempio n. 1
0
/**
 * APR LDAP SSL Initialise function
 *
 * This function initialises SSL on the underlying LDAP toolkit
 * if this is necessary.
 *
 * If a CA certificate is provided, this is set, however the setting
 * of certificates via this method has been deprecated and will be removed in
 * APR v2.0.
 *
 * The apr_ldap_set_option() function with the APR_LDAP_OPT_TLS_CERT option
 * should be used instead to set certificates.
 *
 * If SSL support is not available on this platform, or a problem
 * was encountered while trying to set the certificate, the function
 * will return APR_EGENERAL. Further LDAP specific error information
 * can be found in result_err.
 */
APU_DECLARE_LDAP(int) apr_ldap_ssl_init(apr_pool_t *pool,
                                        const char *cert_auth_file,
                                        int cert_file_type,
                                        apr_ldap_err_t **result_err)
{

    apr_ldap_err_t *result = (apr_ldap_err_t *)apr_pcalloc(pool, sizeof(apr_ldap_err_t));
    *result_err = result;

#if APR_HAS_LDAP_SSL /* compiled with ssl support */

    /* Novell */
#if APR_HAS_NOVELL_LDAPSDK
    ldapssl_client_init(NULL, NULL);
#endif

    /* if a certificate was specified, set it */
    if (cert_auth_file) {
        apr_ldap_opt_tls_cert_t *cert = (apr_ldap_opt_tls_cert_t *)apr_pcalloc(pool, sizeof(apr_ldap_opt_tls_cert_t));
        cert->type = cert_file_type;
        cert->path = cert_auth_file;
        return apr_ldap_set_option(pool, NULL, APR_LDAP_OPT_TLS_CERT, (void *)cert, result_err);
    }

#else  /* not compiled with SSL Support */
    if (cert_auth_file) {
        result->reason = "LDAP: Attempt to set certificate store failed. "
                         "Not built with SSL support";
        result->rc = -1;
    }
#endif /* APR_HAS_LDAP_SSL */

    if (result->rc != -1) {
        result->msg = ldap_err2string(result->rc);
    }

    if (LDAP_SUCCESS != result->rc) {
        return APR_EGENERAL;
    }

    return APR_SUCCESS;

} 
Esempio n. 2
0
static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
{
  CURLcode result = CURLE_OK;
  int rc = 0;
  LDAP *server = NULL;
  LDAPURLDesc *ludp = NULL;
  LDAPMessage *ldapmsg = NULL;
  LDAPMessage *entryIterator;
  int num = 0;
  struct SessionHandle *data=conn->data;
  int ldap_proto = LDAP_VERSION3;
  int ldap_ssl = 0;
  char *val_b64 = NULL;
  size_t val_b64_sz = 0;
  curl_off_t dlsize = 0;
#ifdef LDAP_OPT_NETWORK_TIMEOUT
  struct timeval ldap_timeout = {10,0}; /* 10 sec connection/search timeout */
#endif

  *done = TRUE; /* unconditionally */
  infof(data, "LDAP local: LDAP Vendor = %s ; LDAP Version = %d\n",
          LDAP_VENDOR_NAME, LDAP_VENDOR_VERSION);
  infof(data, "LDAP local: %s\n", data->change.url);

#ifdef HAVE_LDAP_URL_PARSE
  rc = ldap_url_parse(data->change.url, &ludp);
#else
  rc = _ldap_url_parse(conn, &ludp);
#endif
  if(rc != 0) {
    failf(data, "LDAP local: %s", ldap_err2string(rc));
    result = CURLE_LDAP_INVALID_URL;
    goto quit;
  }

  /* Get the URL scheme ( either ldap or ldaps ) */
  if(conn->given->flags & PROTOPT_SSL)
    ldap_ssl = 1;
  infof(data, "LDAP local: trying to establish %s connection\n",
          ldap_ssl ? "encrypted" : "cleartext");

#ifdef LDAP_OPT_NETWORK_TIMEOUT
  ldap_set_option(NULL, LDAP_OPT_NETWORK_TIMEOUT, &ldap_timeout);
#endif
  ldap_set_option(NULL, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto);

  if(ldap_ssl) {
#ifdef HAVE_LDAP_SSL
#ifdef CURL_LDAP_WIN
    /* Win32 LDAP SDK doesn't support insecure mode without CA! */
    server = ldap_sslinit(conn->host.name, (int)conn->port, 1);
    ldap_set_option(server, LDAP_OPT_SSL, LDAP_OPT_ON);
#else
    int ldap_option;
    char* ldap_ca = data->set.str[STRING_SSL_CAFILE];
#if defined(CURL_HAS_NOVELL_LDAPSDK)
    rc = ldapssl_client_init(NULL, NULL);
    if(rc != LDAP_SUCCESS) {
      failf(data, "LDAP local: ldapssl_client_init %s", ldap_err2string(rc));
      result = CURLE_SSL_CERTPROBLEM;
      goto quit;
    }
    if(data->set.ssl.verifypeer) {
      /* Novell SDK supports DER or BASE64 files. */
      int cert_type = LDAPSSL_CERT_FILETYPE_B64;
      if((data->set.str[STRING_CERT_TYPE]) &&
         (Curl_raw_equal(data->set.str[STRING_CERT_TYPE], "DER")))
        cert_type = LDAPSSL_CERT_FILETYPE_DER;
      if(!ldap_ca) {
        failf(data, "LDAP local: ERROR %s CA cert not set!",
              (cert_type == LDAPSSL_CERT_FILETYPE_DER ? "DER" : "PEM"));
        result = CURLE_SSL_CERTPROBLEM;
        goto quit;
      }
      infof(data, "LDAP local: using %s CA cert '%s'\n",
              (cert_type == LDAPSSL_CERT_FILETYPE_DER ? "DER" : "PEM"),
              ldap_ca);
      rc = ldapssl_add_trusted_cert(ldap_ca, cert_type);
      if(rc != LDAP_SUCCESS) {
        failf(data, "LDAP local: ERROR setting %s CA cert: %s",
                (cert_type == LDAPSSL_CERT_FILETYPE_DER ? "DER" : "PEM"),
                ldap_err2string(rc));
        result = CURLE_SSL_CERTPROBLEM;
        goto quit;
      }
      ldap_option = LDAPSSL_VERIFY_SERVER;
    }
    else
      ldap_option = LDAPSSL_VERIFY_NONE;
    rc = ldapssl_set_verify_mode(ldap_option);
    if(rc != LDAP_SUCCESS) {
      failf(data, "LDAP local: ERROR setting cert verify mode: %s",
              ldap_err2string(rc));
      result = CURLE_SSL_CERTPROBLEM;
      goto quit;
    }
    server = ldapssl_init(conn->host.name, (int)conn->port, 1);
    if(server == NULL) {
      failf(data, "LDAP local: Cannot connect to %s:%ld",
              conn->host.name, conn->port);
      result = CURLE_COULDNT_CONNECT;
      goto quit;
    }
#elif defined(LDAP_OPT_X_TLS)
    if(data->set.ssl.verifypeer) {
      /* OpenLDAP SDK supports BASE64 files. */
      if((data->set.str[STRING_CERT_TYPE]) &&
         (!Curl_raw_equal(data->set.str[STRING_CERT_TYPE], "PEM"))) {
        failf(data, "LDAP local: ERROR OpenLDAP only supports PEM cert-type!");
        result = CURLE_SSL_CERTPROBLEM;
        goto quit;
      }
      if(!ldap_ca) {
        failf(data, "LDAP local: ERROR PEM CA cert not set!");
        result = CURLE_SSL_CERTPROBLEM;
        goto quit;
      }
      infof(data, "LDAP local: using PEM CA cert: %s\n", ldap_ca);
      rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE, ldap_ca);
      if(rc != LDAP_SUCCESS) {
        failf(data, "LDAP local: ERROR setting PEM CA cert: %s",
                ldap_err2string(rc));
        result = CURLE_SSL_CERTPROBLEM;
        goto quit;
      }
      ldap_option = LDAP_OPT_X_TLS_DEMAND;
    }
    else
      ldap_option = LDAP_OPT_X_TLS_NEVER;

    rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, &ldap_option);
    if(rc != LDAP_SUCCESS) {
      failf(data, "LDAP local: ERROR setting cert verify mode: %s",
              ldap_err2string(rc));
      result = CURLE_SSL_CERTPROBLEM;
      goto quit;
    }
    server = ldap_init(conn->host.name, (int)conn->port);
    if(server == NULL) {
      failf(data, "LDAP local: Cannot connect to %s:%ld",
              conn->host.name, conn->port);
      result = CURLE_COULDNT_CONNECT;
      goto quit;
    }
    ldap_option = LDAP_OPT_X_TLS_HARD;
    rc = ldap_set_option(server, LDAP_OPT_X_TLS, &ldap_option);
    if(rc != LDAP_SUCCESS) {
      failf(data, "LDAP local: ERROR setting SSL/TLS mode: %s",
              ldap_err2string(rc));
      result = CURLE_SSL_CERTPROBLEM;
      goto quit;
    }
/*
    rc = ldap_start_tls_s(server, NULL, NULL);
    if(rc != LDAP_SUCCESS) {
      failf(data, "LDAP local: ERROR starting SSL/TLS mode: %s",
              ldap_err2string(rc));
      result = CURLE_SSL_CERTPROBLEM;
      goto quit;
    }
*/
#else
    /* we should probably never come up to here since configure
       should check in first place if we can support LDAP SSL/TLS */
    failf(data, "LDAP local: SSL/TLS not supported with this version "
            "of the OpenLDAP toolkit\n");
    result = CURLE_SSL_CERTPROBLEM;
    goto quit;
#endif
#endif
#endif /* CURL_LDAP_USE_SSL */
  }
  else {
    server = ldap_init(conn->host.name, (int)conn->port);
    if(server == NULL) {
      failf(data, "LDAP local: Cannot connect to %s:%ld",
              conn->host.name, conn->port);
      result = CURLE_COULDNT_CONNECT;
      goto quit;
    }
  }
#ifdef CURL_LDAP_WIN
  ldap_set_option(server, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto);
#endif

  rc = ldap_simple_bind_s(server,
                          conn->bits.user_passwd ? conn->user : NULL,
                          conn->bits.user_passwd ? conn->passwd : NULL);
  if(!ldap_ssl && rc != 0) {
    ldap_proto = LDAP_VERSION2;
    ldap_set_option(server, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto);
    rc = ldap_simple_bind_s(server,
                            conn->bits.user_passwd ? conn->user : NULL,
                            conn->bits.user_passwd ? conn->passwd : NULL);
  }
  if(rc != 0) {
    failf(data, "LDAP local: ldap_simple_bind_s %s", ldap_err2string(rc));
    result = CURLE_LDAP_CANNOT_BIND;
    goto quit;
  }

  rc = ldap_search_s(server, ludp->lud_dn, ludp->lud_scope,
                     ludp->lud_filter, ludp->lud_attrs, 0, &ldapmsg);

  if(rc != 0 && rc != LDAP_SIZELIMIT_EXCEEDED) {
    failf(data, "LDAP remote: %s", ldap_err2string(rc));
    result = CURLE_LDAP_SEARCH_FAILED;
    goto quit;
  }

  for(num = 0, entryIterator = ldap_first_entry(server, ldapmsg);
      entryIterator;
      entryIterator = ldap_next_entry(server, entryIterator), num++) {
    BerElement *ber = NULL;
    char  *attribute;       /*! suspicious that this isn't 'const' */
    char  *dn = ldap_get_dn(server, entryIterator);
    int i;

    result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"DN: ", 4);
    if(result)
      goto quit;

    result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)dn, 0);
    if(result)
      goto quit;

    result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1);
    if(result)
      goto quit;

    dlsize += strlen(dn)+5;

    for(attribute = ldap_first_attribute(server, entryIterator, &ber);
        attribute;
        attribute = ldap_next_attribute(server, entryIterator, ber)) {
      BerValue **vals = ldap_get_values_len(server, entryIterator, attribute);

      if(vals != NULL) {
        for(i = 0; (vals[i] != NULL); i++) {
          result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\t", 1);
          if(result)
            goto quit;

          result = Curl_client_write(conn, CLIENTWRITE_BODY,
                                     (char *)attribute, 0);
          if(result)
            goto quit;

          result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)": ", 2);
          if(result)
            goto quit;
          dlsize += strlen(attribute)+3;

          if((strlen(attribute) > 7) &&
              (strcmp(";binary",
                      (char *)attribute +
                      (strlen((char *)attribute) - 7)) == 0)) {
            /* Binary attribute, encode to base64. */
            CURLcode error = Curl_base64_encode(data,
                                                vals[i]->bv_val,
                                                vals[i]->bv_len,
                                                &val_b64,
                                                &val_b64_sz);
            if(error) {
              ldap_value_free_len(vals);
              ldap_memfree(attribute);
              ldap_memfree(dn);
              if(ber)
                ber_free(ber, 0);
              result = error;
              goto quit;
            }
            if(val_b64_sz > 0) {
              result = Curl_client_write(conn, CLIENTWRITE_BODY, val_b64,
                                         val_b64_sz);
              free(val_b64);
              if(result)
                goto quit;
              dlsize += val_b64_sz;
            }
          }
          else {
            result = Curl_client_write(conn, CLIENTWRITE_BODY, vals[i]->bv_val,
                                       vals[i]->bv_len);
            if(result)
              goto quit;
            dlsize += vals[i]->bv_len;
          }
          result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0);
          if(result)
            goto quit;
          dlsize++;
        }

        /* Free memory used to store values */
        ldap_value_free_len(vals);
      }
      result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1);
      if(result)
        goto quit;
      dlsize++;
      Curl_pgrsSetDownloadCounter(data, dlsize);
      ldap_memfree(attribute);
    }
    ldap_memfree(dn);
    if(ber)
       ber_free(ber, 0);
  }

quit:
  if(ldapmsg) {
    ldap_msgfree(ldapmsg);
    LDAP_TRACE (("Received %d entries\n", num));
  }
  if(rc == LDAP_SIZELIMIT_EXCEEDED)
    infof(data, "There are more than %d entries\n", num);
  if(ludp)
    ldap_free_urldesc(ludp);
  if(server)
    ldap_unbind_s(server);
#if defined(HAVE_LDAP_SSL) && defined(CURL_HAS_NOVELL_LDAPSDK)
  if(ldap_ssl)
    ldapssl_client_deinit();
#endif /* HAVE_LDAP_SSL && CURL_HAS_NOVELL_LDAPSDK */

  /* no data to transfer */
  Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
  connclose(conn, "LDAP connection always disable re-use");

  return result;
}
Esempio n. 3
0
/**
 * Handle APR_LDAP_OPT_TLS_CACERTFILE
 *
 * This function sets the CA certificate for further SSL/TLS connections.
 *
 * The file provided are in different formats depending on the toolkit used:
 *
 * Netscape: cert7.db file
 * Novell: PEM or DER
 * OpenLDAP: PEM (others supported?)
 * Microsoft: unknown
 * Solaris: unknown
 */
static void option_set_cert(apr_pool_t *pool, LDAP *ldap,
                           const void *invalue, apr_ldap_err_t *result)
{
#if APR_HAS_LDAP_SSL
#if APR_HAS_LDAPSSL_CLIENT_INIT || APR_HAS_OPENLDAP_LDAPSDK
    apr_array_header_t *certs = (apr_array_header_t *)invalue;
    struct apr_ldap_opt_tls_cert_t *ents = (struct apr_ldap_opt_tls_cert_t *)certs->elts;
    int i = 0;
#endif

    /* Netscape/Mozilla/Solaris SDK */
#if APR_HAS_NETSCAPE_LDAPSDK || APR_HAS_SOLARIS_LDAPSDK || APR_HAS_MOZILLA_LDAPSDK
#if APR_HAS_LDAPSSL_CLIENT_INIT
    const char *nickname = NULL;
    const char *secmod = NULL;
    const char *key3db = NULL;
    const char *cert7db = NULL;
    const char *password = NULL;

    /* set up cert7.db, key3.db and secmod parameters */
    for (i = 0; i < certs->nelts; i++) {
        switch (ents[i].type) {
        case APR_LDAP_CA_TYPE_CERT7_DB:
            cert7db = ents[i].path;
            break;
        case APR_LDAP_CA_TYPE_SECMOD:
            secmod = ents[i].path;
            break;
        case APR_LDAP_CERT_TYPE_KEY3_DB:
            key3db = ents[i].path;
            break;
        case APR_LDAP_CERT_TYPE_NICKNAME:
            nickname = ents[i].path;
            password = ents[i].password;
            break;
        default:
            result->rc = -1;
            result->reason = "LDAP: The Netscape/Mozilla LDAP SDK only "
                "understands the CERT7, KEY3 and SECMOD "
                "file types.";
            break;
        }
        if (result->rc != LDAP_SUCCESS) {
            break;
        }
    }

    /* actually set the certificate parameters */
    if (result->rc == LDAP_SUCCESS) {
        if (nickname) {
            result->rc = ldapssl_enable_clientauth(ldap, "",
                                                   (char *)password,
                                                   (char *)nickname);
            if (result->rc != LDAP_SUCCESS) {
                result->reason = "LDAP: could not set client certificate: "
                                 "ldapssl_enable_clientauth() failed.";
                result->msg = ldap_err2string(result->rc);
            }
        }
        else if (secmod) {
            result->rc = ldapssl_advclientauth_init(cert7db, NULL,
                                                    key3db ? 1 : 0, key3db, NULL,
                                                    1, secmod, LDAPSSL_AUTH_CNCHECK);
            if (result->rc != LDAP_SUCCESS) {
                result->reason = "LDAP: ldapssl_advclientauth_init() failed.";
                result->msg = ldap_err2string(result->rc);
            }
        }
        else if (key3db) {
            result->rc = ldapssl_clientauth_init(cert7db, NULL,
                                                    1, key3db, NULL);
            if (result->rc != LDAP_SUCCESS) {
                result->reason = "LDAP: ldapssl_clientauth_init() failed.";
                result->msg = ldap_err2string(result->rc);
            }
        }
        else {
            result->rc = ldapssl_client_init(cert7db, NULL);
            if (result->rc != LDAP_SUCCESS) {
                result->reason = "LDAP: ldapssl_client_init() failed.";
                result->msg = ldap_err2string(result->rc);
            }
        }
    }
#else
    result->reason = "LDAP: SSL/TLS ldapssl_client_init() function not "
                     "supported by this Netscape/Mozilla/Solaris SDK. "
                     "Certificate authority file not set";
    result->rc = -1;
#endif
#endif

    /* Novell SDK */
#if APR_HAS_NOVELL_LDAPSDK
#if APR_HAS_LDAPSSL_CLIENT_INIT && APR_HAS_LDAPSSL_ADD_TRUSTED_CERT && APR_HAS_LDAPSSL_CLIENT_DEINIT
    /* The Novell library cannot support per connection certificates. Error
     * out if the ldap handle is provided.
     */
    if (ldap) {
        result->rc = -1;
        result->reason = "LDAP: The Novell LDAP SDK cannot support the setting "
                         "of certificates or keys on a per connection basis.";
    }
    /* Novell's library needs to be initialised first */
    else {
        result->rc = ldapssl_client_init(NULL, NULL);
        if (result->rc != LDAP_SUCCESS) {
            result->msg = ldap_err2string(result-> rc);
            result->reason = apr_pstrdup(pool, "LDAP: Could not "
                                         "initialize SSL");
        }
    }
    /* set one or more certificates */
    for (i = 0; LDAP_SUCCESS == result->rc && i < certs->nelts; i++) {
        /* Novell SDK supports DER or BASE64 files. */
        switch (ents[i].type) {
        case APR_LDAP_CA_TYPE_DER:
            result->rc = ldapssl_add_trusted_cert((void *)ents[i].path,
                                                  LDAPSSL_CERT_FILETYPE_DER);
            result->msg = ldap_err2string(result->rc);
            break;
        case APR_LDAP_CA_TYPE_BASE64:
            result->rc = ldapssl_add_trusted_cert((void *)ents[i].path,
                                                  LDAPSSL_CERT_FILETYPE_B64);
            result->msg = ldap_err2string(result->rc);
            break;
        case APR_LDAP_CERT_TYPE_DER:
            result->rc = ldapssl_set_client_cert((void *)ents[i].path,
                                                 LDAPSSL_CERT_FILETYPE_DER,
                                                 (void*)ents[i].password);
            result->msg = ldap_err2string(result->rc);
            break;
        case APR_LDAP_CERT_TYPE_BASE64: 
            result->rc = ldapssl_set_client_cert((void *)ents[i].path,
                                                 LDAPSSL_CERT_FILETYPE_B64,
                                                 (void*)ents[i].password);
            result->msg = ldap_err2string(result->rc);
            break;
        case APR_LDAP_CERT_TYPE_PFX: 
            result->rc = ldapssl_set_client_cert((void *)ents[i].path,
                                                 LDAPSSL_FILETYPE_P12,
                                                 (void*)ents[i].password);
            result->msg = ldap_err2string(result->rc);
            break;
        case APR_LDAP_KEY_TYPE_DER:
            result->rc = ldapssl_set_client_private_key((void *)ents[i].path,
                                                        LDAPSSL_CERT_FILETYPE_DER,
                                                        (void*)ents[i].password);
            result->msg = ldap_err2string(result->rc);
            break;
        case APR_LDAP_KEY_TYPE_BASE64:
            result->rc = ldapssl_set_client_private_key((void *)ents[i].path,
                                                        LDAPSSL_CERT_FILETYPE_B64,
                                                        (void*)ents[i].password);
            result->msg = ldap_err2string(result->rc);
            break;
        case APR_LDAP_KEY_TYPE_PFX:
            result->rc = ldapssl_set_client_private_key((void *)ents[i].path,
                                                        LDAPSSL_FILETYPE_P12,
                                                        (void*)ents[i].password);
            result->msg = ldap_err2string(result->rc);
            break;
        default:
            result->rc = -1;
            result->reason = "LDAP: The Novell LDAP SDK only understands the "
                "DER and PEM (BASE64) file types.";
            break;
        }
        if (result->rc != LDAP_SUCCESS) {
            break;
        }
    }
#else
    result->reason = "LDAP: ldapssl_client_init(), "
                     "ldapssl_add_trusted_cert() or "
                     "ldapssl_client_deinit() functions not supported "
                     "by this Novell SDK. Certificate authority file "
                     "not set";
    result->rc = -1;
#endif
#endif

    /* OpenLDAP SDK */
#if APR_HAS_OPENLDAP_LDAPSDK
#ifdef LDAP_OPT_X_TLS_CACERTFILE
    /* set one or more certificates */
    /* FIXME: make it support setting directories as well as files */
    for (i = 0; i < certs->nelts; i++) {
        /* OpenLDAP SDK supports BASE64 files. */
        switch (ents[i].type) {
        case APR_LDAP_CA_TYPE_BASE64:
            result->rc = ldap_set_option(ldap, LDAP_OPT_X_TLS_CACERTFILE,
                                         (void *)ents[i].path);
            result->msg = ldap_err2string(result->rc);
            break;
        case APR_LDAP_CERT_TYPE_BASE64:
            result->rc = ldap_set_option(ldap, LDAP_OPT_X_TLS_CERTFILE,
                                         (void *)ents[i].path);
            result->msg = ldap_err2string(result->rc);
            break;
        case APR_LDAP_KEY_TYPE_BASE64:
            result->rc = ldap_set_option(ldap, LDAP_OPT_X_TLS_KEYFILE,
                                         (void *)ents[i].path);
            result->msg = ldap_err2string(result->rc);
            break;
#ifdef LDAP_OPT_X_TLS_CACERTDIR
        case APR_LDAP_CA_TYPE_CACERTDIR_BASE64:
            result->rc = ldap_set_option(ldap, LDAP_OPT_X_TLS_CACERTDIR,
                                         (void *)ents[i].path);
            result->msg = ldap_err2string(result->rc);
            break;
#endif
        default:
            result->rc = -1;
            result->reason = "LDAP: The OpenLDAP SDK only understands the "
                "PEM (BASE64) file type.";
            break;
        }
        if (result->rc != LDAP_SUCCESS) {
            break;
        }
    }
#else
    result->reason = "LDAP: LDAP_OPT_X_TLS_CACERTFILE not "
                     "defined by this OpenLDAP SDK. Certificate "
                     "authority file not set";
    result->rc = -1;
#endif
#endif

    /* Microsoft SDK */
#if APR_HAS_MICROSOFT_LDAPSDK
    /* Microsoft SDK use the registry certificate store - error out
     * here with a message explaining this. */
    result->reason = "LDAP: CA certificates cannot be set using this method, "
                     "as they are stored in the registry instead.";
    result->rc = -1;
#endif

    /* SDK not recognised */
#if APR_HAS_OTHER_LDAPSDK
    result->reason = "LDAP: LDAP_OPT_X_TLS_CACERTFILE not "
                     "defined by this LDAP SDK. Certificate "
                     "authority file not set";
    result->rc = -1;
#endif

#else  /* not compiled with SSL Support */
    result->reason = "LDAP: Attempt to set certificate(s) failed. "
                     "Not built with SSL support";
    result->rc = -1;
#endif /* APR_HAS_LDAP_SSL */

}
Esempio n. 4
0
int
main( int argc, char **argv )
{
	LDAP		*ld;
	LDAPMessage	*result, *e;
	BerElement	*ber;
	char		*a, *dn;
	char		**vals;
	int		i;

	/* Initialize the client */
	if ( ldapssl_client_init( MY_CERTDB_PATH, NULL ) < 0 ) {
		perror( "ldapssl_client_init" );
		return( 1 );
	}

	/* set the max I/O timeout option to 10 seconds */
	if ( prldap_set_session_option( NULL, NULL, PRLDAP_OPT_IO_MAX_TIMEOUT,
	    10000 /* 10 secs */ ) != LDAP_SUCCESS ) {
		ldap_perror( NULL,
		    "prldap_set_session_option PRLDAP_OPT_IO_MAX_TIMEOUT" );
		exit( 1 );
	}

	/* get a handle to an LDAP connection */
	if ( (ld = ldapssl_init( MY_HOST, MY_SSL_PORT, 1 )) == NULL ) {
		perror( "ldapssl_init" );
		return( 1 );
	}

	/* use LDAPv3 */
	i = LDAP_VERSION3;
	if ( ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &i ) < 0 ) {
		ldap_perror( ld, "ldap_set_option LDAPv3" );
		ldap_unbind( ld );
		return( 1 );
	}

	/* search for all entries with surname of Jensen */
	if ( ldap_search_s( ld, PEOPLE_BASE, LDAP_SCOPE_SUBTREE,
		"(sn=jensen)", NULL, 0, &result ) != LDAP_SUCCESS ) {
		ldap_perror( ld, "ldap_search_s" );
		if ( result == NULL ) {
			ldap_unbind( ld );
			return( 1 );
		}
	}
	/* for each entry print out name + all attrs and values */
	for ( e = ldap_first_entry( ld, result ); e != NULL;
	    e = ldap_next_entry( ld, e ) ) {
		if ( (dn = ldap_get_dn( ld, e )) != NULL ) {
		    printf( "dn: %s\n", dn );
		    ldap_memfree( dn );
		}
		for ( a = ldap_first_attribute( ld, e, &ber );
		    a != NULL; a = ldap_next_attribute( ld, e, ber ) ) {
			if ((vals = ldap_get_values( ld, e, a)) != NULL ) {
				for ( i = 0; vals[i] != NULL; i++ ) {
				    printf( "%s: %s\n", a, vals[i] );
				}
				ldap_value_free( vals );
			}
			ldap_memfree( a );
		}
		if ( ber != NULL ) {
			ber_free( ber, 0 );
		}
		printf( "\n" );
	}
	ldap_msgfree( result );
	ldap_unbind( ld );
	return( 0 );
}
static void
ldapconnect(void)
{
    int rc;

/* On Windows ldap_start_tls_s is available starting from Windows XP, 
 * so we need to bind at run-time with the function entry point
 */
#ifdef _SQUID_MSWIN_
    if (use_tls) {

	HMODULE WLDAP32Handle;

	WLDAP32Handle = GetModuleHandle("wldap32");
	if ((Win32_ldap_start_tls_s = (PFldap_start_tls_s) GetProcAddress(WLDAP32Handle, LDAP_START_TLS_S)) == NULL) {
	    fprintf(stderr, PROGRAM_NAME ": ERROR: TLS (-Z) not supported on this platform.\n");
	    exit(1);
	}
    }
#endif

    if (ld == NULL) {
#if HAS_URI_SUPPORT
	if (strstr(ldapServer, "://") != NULL) {
	    rc = ldap_initialize(&ld, ldapServer);
	    if (rc != LDAP_SUCCESS) {
		fprintf(stderr, "\nUnable to connect to LDAPURI:%s\n", ldapServer);
	    }
	} else
#endif
#if NETSCAPE_SSL
	if (sslpath) {
	    if (!sslinit && (ldapssl_client_init(sslpath, NULL) != LDAP_SUCCESS)) {
		fprintf(stderr, "\nUnable to initialise SSL with cert path %s\n",
		    sslpath);
		exit(1);
	    } else {
		sslinit++;
	    }
	    if ((ld = ldapssl_init(ldapServer, port, 1)) == NULL) {
		fprintf(stderr, "\nUnable to connect to SSL LDAP server: %s port:%d\n",
		    ldapServer, port);
		exit(1);
	    }
	} else
#endif
	if ((ld = ldap_init(ldapServer, port)) == NULL) {
	    fprintf(stderr, "\nUnable to connect to LDAP server:%s port:%d\n", ldapServer, port);
	}
	if (connect_timeout)
	    squid_ldap_set_connect_timeout(connect_timeout);

#ifdef LDAP_VERSION3
	if (version == -1) {
	    version = LDAP_VERSION2;
	}
	if (ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &version)
	    != LDAP_SUCCESS) {
	    fprintf(stderr, "Could not set LDAP_OPT_PROTOCOL_VERSION %d\n",
		version);
	    ldap_unbind(ld);
	    ld = NULL;
	}
	if (use_tls) {
#ifdef LDAP_OPT_X_TLS
	    if ((version == LDAP_VERSION3) && (ldap_start_tls_s(ld, NULL, NULL) == LDAP_SUCCESS)) {
		fprintf(stderr, "Could not Activate TLS connection\n");
		ldap_unbind(ld);
		ld = NULL;
	    }
#else
	    fprintf(stderr, "TLS not supported with your LDAP library\n");
	    ldap_unbind(ld);
	    ld = NULL;
#endif
	}
#endif
	squid_ldap_set_timelimit(timelimit);
	squid_ldap_set_referrals(!noreferrals);
	squid_ldap_set_aliasderef(aliasderef);
	if (binddn && bindpasswd && *binddn && *bindpasswd) {
	    rc = ldap_simple_bind_s(ld, binddn, bindpasswd);
	    if (rc != LDAP_SUCCESS) {
		fprintf(stderr, PROGRAM_NAME " WARNING, could not bind to binddn '%s'\n", ldap_err2string(rc));
		ldap_unbind(ld);
		ld = NULL;
	    }
	}
	if (debug)
	    fprintf(stderr, "Connected OK\n");
    }
}
Esempio n. 6
0
int
main(int argc, char **argv)
{
    char buf[8192];
    char *user, *group, *extension_dn = NULL;
    char *ldapServer = NULL;
    LDAP *ld = NULL;
    int tryagain = 0, rc;
    int port = LDAP_PORT;
    int use_extension_dn = 0;
    int strip_nt_domain = 0;
    int strip_kerberos_realm = 0;

    setbuf(stdout, NULL);

    while (argc > 1 && argv[1][0] == '-') {
	char *value = "";
	char option = argv[1][1];
	switch (option) {
	case 'P':
	case 'R':
	case 'z':
	case 'Z':
	case 'd':
	case 'g':
	case 'S':
	case 'K':
	    break;
	default:
	    if (strlen(argv[1]) > 2) {
		value = argv[1] + 2;
	    } else if (argc > 2) {
		value = argv[2];
		argv++;
		argc--;
	    } else
		value = "";
	    break;
	}
	argv++;
	argc--;
	switch (option) {
	case 'H':
#if !HAS_URI_SUPPORT
	    fprintf(stderr, "ERROR: Your LDAP library does not have URI support\n");
	    exit(1);
#endif
	    /* Fall thru to -h */
	case 'h':
	    if (ldapServer) {
		int len = strlen(ldapServer) + 1 + strlen(value) + 1;
		char *newhost = malloc(len);
		snprintf(newhost, len, "%s %s", ldapServer, value);
		free(ldapServer);
		ldapServer = newhost;
	    } else {
		ldapServer = strdup(value);
	    }
	    break;
	case 'b':
	    basedn = value;
	    break;
	case 'f':
	    searchfilter = value;
	    break;
	case 'B':
	    userbasedn = value;
	    break;
	case 'F':
	    usersearchfilter = value;
	    break;
	case 'u':
	    userdnattr = value;
	    break;
	case 's':
	    if (strcmp(value, "base") == 0)
		searchscope = LDAP_SCOPE_BASE;
	    else if (strcmp(value, "one") == 0)
		searchscope = LDAP_SCOPE_ONELEVEL;
	    else if (strcmp(value, "sub") == 0)
		searchscope = LDAP_SCOPE_SUBTREE;
	    else {
		fprintf(stderr, PROGRAM_NAME " ERROR: Unknown search scope '%s'\n", value);
		exit(1);
	    }
	    break;
	case 'E':
#if defined(NETSCAPE_SSL)
	    sslpath = value;
	    if (port == LDAP_PORT)
		port = LDAPS_PORT;
#else
	    fprintf(stderr, PROGRAM_NAME " ERROR: -E unsupported with this LDAP library\n");
	    exit(1);
#endif
	    break;
	case 'c':
	    connect_timeout = atoi(value);
	    break;
	case 't':
	    timelimit = atoi(value);
	    break;
	case 'a':
	    if (strcmp(value, "never") == 0)
		aliasderef = LDAP_DEREF_NEVER;
	    else if (strcmp(value, "always") == 0)
		aliasderef = LDAP_DEREF_ALWAYS;
	    else if (strcmp(value, "search") == 0)
		aliasderef = LDAP_DEREF_SEARCHING;
	    else if (strcmp(value, "find") == 0)
		aliasderef = LDAP_DEREF_FINDING;
	    else {
		fprintf(stderr, PROGRAM_NAME " ERROR: Unknown alias dereference method '%s'\n", value);
		exit(1);
	    }
	    break;
	case 'D':
	    binddn = value;
	    break;
	case 'w':
	    bindpasswd = value;
	    break;
	case 'W':
	    readSecret(value);
	    break;
	case 'P':
	    persistent = !persistent;
	    break;
	case 'p':
	    port = atoi(value);
	    break;
	case 'R':
	    noreferrals = !noreferrals;
	    break;
#ifdef LDAP_VERSION3
	case 'v':
	    switch (atoi(value)) {
	    case 2:
		version = LDAP_VERSION2;
		break;
	    case 3:
		version = LDAP_VERSION3;
		break;
	    default:
		fprintf(stderr, "Protocol version should be 2 or 3\n");
		exit(1);
	    }
	    break;
	case 'Z':
	    if (version == LDAP_VERSION2) {
		fprintf(stderr, "TLS (-Z) is incompatible with version %d\n",
		    version);
		exit(1);
	    }
	    version = LDAP_VERSION3;
	    use_tls = 1;
	    break;
#endif
	case 'd':
	    debug = 1;
	    break;
	case 'g':
	    use_extension_dn = 1;
	    break;
	case 'S':
	    strip_nt_domain = 1;
	    break;
	case 'K':
	    strip_kerberos_realm = 1;
	    break;
	default:
	    fprintf(stderr, PROGRAM_NAME " ERROR: Unknown command line option '%c'\n", option);
	    exit(1);
	}
    }

    while (argc > 1) {
	char *value = argv[1];
	if (ldapServer) {
	    int len = strlen(ldapServer) + 1 + strlen(value) + 1;
	    char *newhost = malloc(len);
	    snprintf(newhost, len, "%s %s", ldapServer, value);
	    free(ldapServer);
	    ldapServer = newhost;
	} else {
	    ldapServer = strdup(value);
	}
	argc--;
	argv++;
    }

    if (!ldapServer)
	ldapServer = "localhost";

    if (!basedn || !searchfilter) {
	fprintf(stderr, "\n" PROGRAM_NAME " version " PROGRAM_VERSION "\n\n");
	fprintf(stderr, "Usage: " PROGRAM_NAME " -b basedn -f filter [options] ldap_server_name\n\n");
	fprintf(stderr, "\t-b basedn (REQUIRED)\tbase dn under where to search for groups\n");
	fprintf(stderr, "\t-f filter (REQUIRED)\tgroup search filter pattern. %%u = user,\n\t\t\t\t%%g = group\n");
	fprintf(stderr, "\t-B basedn (REQUIRED)\tbase dn under where to search for users\n");
	fprintf(stderr, "\t-F filter (REQUIRED)\tuser search filter pattern. %%s = login\n");
	fprintf(stderr, "\t-s base|one|sub\t\tsearch scope\n");
	fprintf(stderr, "\t-D binddn\t\tDN to bind as to perform searches\n");
	fprintf(stderr, "\t-w bindpasswd\t\tpassword for binddn\n");
	fprintf(stderr, "\t-W secretfile\t\tread password for binddn from file secretfile\n");
#if HAS_URI_SUPPORT
	fprintf(stderr, "\t-H URI\t\t\tLDAPURI (defaults to ldap://localhost)\n");
#endif
	fprintf(stderr, "\t-h server\t\tLDAP server (defaults to localhost)\n");
	fprintf(stderr, "\t-p port\t\t\tLDAP server port (defaults to %d)\n", LDAP_PORT);
	fprintf(stderr, "\t-P\t\t\tpersistent LDAP connection\n");
#if defined(NETSCAPE_SSL)
	fprintf(stderr, "\t-E sslcertpath\t\tenable LDAP over SSL\n");
#endif
	fprintf(stderr, "\t-c timeout\t\tconnect timeout\n");
	fprintf(stderr, "\t-t timelimit\t\tsearch time limit\n");
	fprintf(stderr, "\t-R\t\t\tdo not follow referrals\n");
	fprintf(stderr, "\t-a never|always|search|find\n\t\t\t\twhen to dereference aliases\n");
#ifdef LDAP_VERSION3
	fprintf(stderr, "\t-v 2|3\t\t\tLDAP version\n");
	fprintf(stderr, "\t-Z\t\t\tTLS encrypt the LDAP connection, requires\n\t\t\t\tLDAP version 3\n");
#endif
	fprintf(stderr, "\t-g\t\t\tfirst query parameter is base DN extension\n\t\t\t\tfor this query\n");
	fprintf(stderr, "\t-S\t\t\tStrip NT domain from usernames\n");
	fprintf(stderr, "\t-K\t\t\tStrip Kerberos realm from usernames\n");
	fprintf(stderr, "\t-d\t\t\tenable debug mode\n");
	fprintf(stderr, "\n");
	fprintf(stderr, "\tIf you need to bind as a user to perform searches then use the\n\t-D binddn -w bindpasswd or -D binddn -W secretfile options\n\n");
	exit(1);
    }
/* On Windows ldap_start_tls_s is available starting from Windows XP, 
 * so we need to bind at run-time with the function entry point
 */
#ifdef _SQUID_MSWIN_
    if (use_tls) {

	HMODULE WLDAP32Handle;

	WLDAP32Handle = GetModuleHandle("wldap32");
	if ((Win32_ldap_start_tls_s = (PFldap_start_tls_s) GetProcAddress(WLDAP32Handle, LDAP_START_TLS_S)) == NULL) {
	    fprintf(stderr, PROGRAM_NAME ": ERROR: TLS (-Z) not supported on this platform.\n");
	    exit(1);
	}
    }
#endif

    while (fgets(buf, 256, stdin) != NULL) {
	int found = 0;
	if (!strchr(buf, '\n')) {
	    /* too large message received.. skip and deny */
	    fprintf(stderr, "%s: ERROR: Too large: %s\n", argv[0], buf);
	    while (fgets(buf, sizeof(buf), stdin)) {
		fprintf(stderr, "%s: ERROR: Too large..: %s\n", argv[0], buf);
		if (strchr(buf, '\n') != NULL)
		    break;
	    }
	    goto error;
	}
	user = strtok(buf, " \n");
	if (!user) {
	    fprintf(stderr, "%s: Invalid request\n", argv[0]);
	    goto error;
	}
	rfc1738_unescape(user);
	if (strip_nt_domain) {
	    char *u = strrchr(user, '\\');
	    if (!u)
		u = strrchr(user, '/');
	    if (!u)
		u = strrchr(user, '+');
	    if (u && u[1])
		user = u + 1;
	}
	if (strip_kerberos_realm) {
	    char *u = strchr(user, '@');
	    if (u != NULL) {
		*u = '\0';
	    }
	}
	if (use_extension_dn) {
	    extension_dn = strtok(NULL, " \n");
	    if (!extension_dn) {
		fprintf(stderr, "%s: Invalid request\n", argv[0]);
		goto error;
	    }
	    rfc1738_unescape(extension_dn);
	}
	while (!found && user && (group = strtok(NULL, " \n")) != NULL) {
	    rfc1738_unescape(group);

	  recover:
	    if (ld == NULL) {
#if HAS_URI_SUPPORT
		if (strstr(ldapServer, "://") != NULL) {
		    rc = ldap_initialize(&ld, ldapServer);
		    if (rc != LDAP_SUCCESS) {
			fprintf(stderr, "\nUnable to connect to LDAPURI:%s\n", ldapServer);
			break;
		    }
		} else
#endif
#if NETSCAPE_SSL
		if (sslpath) {
		    if (!sslinit && (ldapssl_client_init(sslpath, NULL) != LDAP_SUCCESS)) {
			fprintf(stderr, "\nUnable to initialise SSL with cert path %s\n",
			    sslpath);
			exit(1);
		    } else {
			sslinit++;
		    }
		    if ((ld = ldapssl_init(ldapServer, port, 1)) == NULL) {
			fprintf(stderr, "\nUnable to connect to SSL LDAP server: %s port:%d\n",
			    ldapServer, port);
			exit(1);
		    }
		} else
#endif
		if ((ld = ldap_init(ldapServer, port)) == NULL) {
		    fprintf(stderr, "\nUnable to connect to LDAP server:%s port:%d\n", ldapServer, port);
		    break;
		}
		if (connect_timeout)
		    squid_ldap_set_connect_timeout(ld, connect_timeout);

#ifdef LDAP_VERSION3
		if (version == -1) {
		    version = LDAP_VERSION2;
		}
		if (ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &version) != LDAP_SUCCESS) {
		    fprintf(stderr, "Could not set LDAP_OPT_PROTOCOL_VERSION %d\n",
			version);
		    ldap_unbind(ld);
		    ld = NULL;
		    break;
		}
		if (use_tls) {
#ifdef LDAP_OPT_X_TLS
		    if (version != LDAP_VERSION3) {
			fprintf(stderr, "TLS requires LDAP version 3\n");
			exit(1);
		    } else if (ldap_start_tls_s(ld, NULL, NULL) != LDAP_SUCCESS) {
			fprintf(stderr, "Could not Activate TLS connection\n");
			ldap_unbind(ld);
			ld = NULL;
			break;
		    }
#else
		    fprintf(stderr, "TLS not supported with your LDAP library\n");
		    exit(1);
#endif
		}
#endif
		squid_ldap_set_timelimit(ld, timelimit);
		squid_ldap_set_referrals(ld, !noreferrals);
		squid_ldap_set_aliasderef(ld, aliasderef);
		if (binddn && bindpasswd && *binddn && *bindpasswd) {
		    rc = ldap_simple_bind_s(ld, binddn, bindpasswd);
		    if (rc != LDAP_SUCCESS) {
			fprintf(stderr, PROGRAM_NAME " WARNING, could not bind to binddn '%s'\n", ldap_err2string(rc));
			ldap_unbind(ld);
			ld = NULL;
			break;
		    }
		}
		if (debug)
		    fprintf(stderr, "Connected OK\n");
	    }
	    if (searchLDAP(ld, group, user, extension_dn) == 0) {
		found = 1;
		break;
	    } else {
		if (tryagain) {
		    tryagain = 0;
		    ldap_unbind(ld);
		    ld = NULL;
		    goto recover;
		}
	    }
	}
	if (found)
	    printf("OK\n");
	else {
	  error:
	    printf("ERR\n");
	}

	if (ld != NULL) {
	    if (!persistent || (squid_ldap_errno(ld) != LDAP_SUCCESS && squid_ldap_errno(ld) != LDAP_INVALID_CREDENTIALS)) {
		ldap_unbind(ld);
		ld = NULL;
	    } else {
		tryagain = 1;
	    }
	}
    }
    if (ld)
	ldap_unbind(ld);
    return 0;
}
Esempio n. 7
0
/*
 * Do an LDAP lookup to the server described in the info argument.
 *
 * Args      info -- LDAP info for server.
 *         string -- String to lookup.
 *           cust -- Possible custom filter description.
 *         wp_err -- We set this is we get a white pages error.
 *  name_in_error -- Caller sets this if they want us to include the server
 *                   name in error messages.
 *
 * Returns  Results of lookup, NULL if lookup failed.
 */
LDAP_SERV_RES_S *
ldap_lookup(LDAP_SERV_S *info, char *string, CUSTOM_FILT_S *cust,
	    WP_ERR_S *wp_err, int name_in_error)
{
    char     ebuf[900];
    char     buf[900];
    char    *serv, *base, *serv_errstr;
    char    *mailattr, *snattr, *gnattr, *cnattr;
    int      we_cancel = 0, we_turned_on = 0;
    LDAP_SERV_RES_S *serv_res = NULL;
    LDAP *ld;
    long  pwdtrial = 0L;
    int   ld_errnum;
    char *ld_errstr;


    if(!info)
      return(serv_res);

    serv = cpystr((info->serv && *info->serv) ? info->serv : "?");

    if(name_in_error)
      snprintf(ebuf, sizeof(ebuf), " (%s)",
	      (info->nick && *info->nick) ? info->nick : serv);
    else
      ebuf[0] = '\0';

    serv_errstr = cpystr(ebuf);
    base = cpystr(info->base ? info->base : "");

    if(info->port < 0)
      info->port = LDAP_PORT;

    if(info->type < 0)
      info->type = DEF_LDAP_TYPE;

    if(info->srch < 0)
      info->srch = DEF_LDAP_SRCH;
	
    if(info->time < 0)
      info->time = DEF_LDAP_TIME;

    if(info->size < 0)
      info->size = DEF_LDAP_SIZE;

    if(info->scope < 0)
      info->scope = DEF_LDAP_SCOPE;

    mailattr = (info->mailattr && info->mailattr[0]) ? info->mailattr
						     : DEF_LDAP_MAILATTR;
    snattr = (info->snattr && info->snattr[0]) ? info->snattr
						     : DEF_LDAP_SNATTR;
    gnattr = (info->gnattr && info->gnattr[0]) ? info->gnattr
						     : DEF_LDAP_GNATTR;
    cnattr = (info->cnattr && info->cnattr[0]) ? info->cnattr
						     : DEF_LDAP_CNATTR;

    /*
     * We may want to keep ldap handles open, but at least for
     * now, re-open them every time.
     */

    dprint((3, "ldap_lookup(%s,%d)\n", serv ? serv : "?", info->port));

    snprintf(ebuf, sizeof(ebuf), "Searching%s%s%s on %s",
	    (string && *string) ? " for \"" : "",
	    (string && *string) ? string : "",
	    (string && *string) ? "\"" : "",
	    serv);
    we_turned_on = intr_handling_on();		/* this erases keymenu */
    we_cancel = busy_cue(ebuf, NULL, 0);
    if(wp_err->mangled)
      *(wp_err->mangled) = 1;

#ifdef _SOLARIS_SDK
    if(info->tls || info->tlsmust)
      ldapssl_client_init(NULL, NULL);
    if((ld = ldap_init(serv, info->port)) == NULL)
#else
#if (LDAPAPI >= 11)
    if((ld = ldap_init(serv, info->port)) == NULL)
#else
    if((ld = ldap_open(serv, info->port)) == NULL)
#endif
#endif
    {
      /* TRANSLATORS: All of the three args together are an error message */
      snprintf(ebuf, sizeof(ebuf), _("Access to LDAP server failed: %s%s(%s)"),
	      errno ? error_description(errno) : "",
	      errno ? " " : "",
	      serv);
      wp_err->wp_err_occurred = 1;
      if(wp_err->error)
	fs_give((void **)&wp_err->error);

      wp_err->error = cpystr(ebuf);
      if(we_cancel)
        cancel_busy_cue(-1);

      q_status_message(SM_ORDER, 3, 5, wp_err->error);
      display_message('x');
      dprint((2, "%s\n", ebuf));
    }
    else if(!ps_global->intr_pending){
      int proto = 3, tlsmustbail = 0;
      char pwd[NETMAXPASSWD], user[NETMAXUSER];
      char *passwd = NULL;
      char hostbuf[1024];
      NETMBX mb;
#ifndef _WINDOWS
      int rc;
#endif

      memset(&mb, 0, sizeof(mb));

#ifdef _SOLARIS_SDK
      if(info->tls || info->tlsmust)
	rc = ldapssl_install_routines(ld);
#endif

      if(ldap_v3_is_supported(ld) &&
	 our_ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &proto) == 0){
	dprint((5, "ldap: using version 3 protocol\n"));
      }

      /*
       * If we don't set RESTART then the select() waiting for the answer
       * in libldap will be interrupted and stopped by our busy_cue.
       */
      our_ldap_set_option(ld, LDAP_OPT_RESTART, LDAP_OPT_ON);

      /*
       * If we need to authenticate, get the password. We are not
       * supporting SASL authentication, just LDAP simple.
       */
      if(info->binddn && info->binddn[0]){
	  char pmt[500];
	  char *space;

	  snprintf(hostbuf, sizeof(hostbuf), "{%s}dummy", info->serv ? info->serv : "?");

	  /*
	   * We don't handle multiple space-delimited hosts well.
	   * We don't know which we're asking for a password for.
	   * We're not connected yet so we can't know.
	   */
	  if((space=strindex(hostbuf, ' ')) != NULL)
	    *space = '\0';

	  mail_valid_net_parse_work(hostbuf, &mb, "ldap");
	  mb.port = info->port;
	  mb.tlsflag = (info->tls || info->tlsmust) ? 1 : 0;

try_password_again:

	  if(mb.tlsflag
	     && (pwdtrial > 0 || 
#ifndef _WINDOWS
#ifdef _SOLARIS_SDK
		 (rc == LDAP_SUCCESS)
#else /* !_SOLARIS_SDK */
		 ((rc=ldap_start_tls_s(ld, NULL, NULL)) == LDAP_SUCCESS)
#endif /* !_SOLARIS_SDK */
#else /* _WINDOWS */
		 0  /* TODO: find a way to do this in Windows */
#endif /* _WINDOWS */
		 ))
	    mb.tlsflag = 1;
	  else
	    mb.tlsflag = 0;

	  if((info->tls || info->tlsmust) && !mb.tlsflag){
	    q_status_message(SM_ORDER, 3, 5, "Not able to start TLS encryption for LDAP server");
	    if(info->tlsmust)
	      tlsmustbail++;
	  }

	  if(!tlsmustbail){
	      snprintf(pmt, sizeof(pmt), "  %s", (info->nick && *info->nick) ? info->nick : serv);
	      mm_login_work(&mb, user, pwd, pwdtrial, pmt, info->binddn);
	      if(pwd && pwd[0])
		passwd = pwd;
	  }
      }


      /*
       * LDAPv2 requires the bind. v3 doesn't require it but we want
       * to tell the server we're v3 if the server supports v3, and if the
       * server doesn't support v3 the bind is required.
       */
      if(tlsmustbail || ldap_simple_bind_s(ld, info->binddn, passwd) != LDAP_SUCCESS){
	wp_err->wp_err_occurred = 1;

	ld_errnum = our_ldap_get_lderrno(ld, NULL, &ld_errstr);

        if(!tlsmustbail && info->binddn && info->binddn[0] && pwdtrial < 2L
	   && ld_errnum == LDAP_INVALID_CREDENTIALS){
	  pwdtrial++;
          q_status_message(SM_ORDER, 3, 5, _("Invalid password"));
	  goto try_password_again;
	}

	snprintf(ebuf, sizeof(ebuf), _("LDAP server failed: %s%s%s%s"),
		ldap_err2string(ld_errnum),
		serv_errstr,
		(ld_errstr && *ld_errstr) ? ": " : "",
		(ld_errstr && *ld_errstr) ? ld_errstr : "");

        if(wp_err->error)
	  fs_give((void **)&wp_err->error);

        if(we_cancel)
          cancel_busy_cue(-1);

	ldap_unbind(ld);
        wp_err->error = cpystr(ebuf);
        q_status_message(SM_ORDER, 3, 5, wp_err->error);
        display_message('x');
	dprint((2, "%s\n", ebuf));
      }
      else if(!ps_global->intr_pending){
	int          srch_res, args, slen, flen;
#define TEMPLATELEN 512
	char         filt_template[TEMPLATELEN + 1];
	char         filt_format[2*TEMPLATELEN + 1];
	char         filter[2*TEMPLATELEN + 1];
	char         scp[2*TEMPLATELEN + 1];
	char        *p, *q;
	LDAPMessage *res = NULL;
	int intr_happened = 0;
	int tl;

	tl = (info->time == 0) ? info->time : info->time + 10;

	our_ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &tl);
	our_ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &info->size);

	/*
	 * If a custom filter has been passed in and it doesn't include a
	 * request to combine it with the configured filter, then replace
	 * any configured filter with the passed in filter.
	 */
	if(cust && cust->filt && !cust->combine){
	    if(info->cust)
	      fs_give((void **)&info->cust);
	    
	    info->cust = cpystr(cust->filt);
	}

	if(info->cust && *info->cust){	/* use custom filter if present */
	    strncpy(filt_template, info->cust, sizeof(filt_template));
	    filt_template[sizeof(filt_template)-1] = '\0';
	}
	else{				/* else use configured filter */
	    switch(info->type){
	      case LDAP_TYPE_SUR:
		snprintf(filt_template, sizeof(filt_template), "(%s=%%s)", snattr);
		break;
	      case LDAP_TYPE_GIVEN:
		snprintf(filt_template, sizeof(filt_template), "(%s=%%s)", gnattr);
		break;
	      case LDAP_TYPE_EMAIL:
		snprintf(filt_template, sizeof(filt_template), "(%s=%%s)", mailattr);
		break;
	      case LDAP_TYPE_CN_EMAIL:
		snprintf(filt_template, sizeof(filt_template), "(|(%s=%%s)(%s=%%s))", cnattr,
			mailattr);
		break;
	      case LDAP_TYPE_SUR_GIVEN:
		snprintf(filt_template, sizeof(filt_template), "(|(%s=%%s)(%s=%%s))",
			snattr, gnattr);
		break;
	      case LDAP_TYPE_SEVERAL:
		snprintf(filt_template, sizeof(filt_template),
			"(|(%s=%%s)(%s=%%s)(%s=%%s)(%s=%%s))",
			cnattr, mailattr, snattr, gnattr);
		break;
	      default:
	      case LDAP_TYPE_CN:
		snprintf(filt_template, sizeof(filt_template), "(%s=%%s)", cnattr);
		break;
	    }
	}

	/* just copy if custom */
	if(info->cust && *info->cust)
	  info->srch = LDAP_SRCH_EQUALS;

	p = filt_template;
	q = filt_format;
	memset((void *)filt_format, 0, sizeof(filt_format));
	args = 0;
	while(*p && (q - filt_format) + 4 < sizeof(filt_format)){
	    if(*p == '%' && *(p+1) == 's'){
		args++;
		switch(info->srch){
		  /* Exact match */
		  case LDAP_SRCH_EQUALS:
		    *q++ = *p++;
		    *q++ = *p++;
		    break;

		  /* Append wildcard after %s */
		  case LDAP_SRCH_BEGINS:
		    *q++ = *p++;
		    *q++ = *p++;
		    *q++ = '*';
		    break;

		  /* Insert wildcard before %s */
		  case LDAP_SRCH_ENDS:
		    *q++ = '*';
		    *q++ = *p++;
		    *q++ = *p++;
		    break;

		  /* Put wildcard before and after %s */
		  default:
		  case LDAP_SRCH_CONTAINS:
		    *q++ = '*';
		    *q++ = *p++;
		    *q++ = *p++;
		    *q++ = '*';
		    break;
		}
	    }
	    else
	      *q++ = *p++;
	}

	if(q - filt_format < sizeof(filt_format))
	  *q = '\0';

	filt_format[sizeof(filt_format)-1] = '\0';

	/*
	 * If combine is lit we put the custom filter and the filt_format
	 * filter and combine them with an &.
	 */
	if(cust && cust->filt && cust->combine){
	    char *combined;
	    size_t l;

	    l = strlen(filt_format) + strlen(cust->filt) + 3;
	    combined = (char *) fs_get((l+1) * sizeof(char));
	    snprintf(combined, l+1, "(&%s%s)", cust->filt, filt_format);
	    strncpy(filt_format, combined, sizeof(filt_format));
	    filt_format[sizeof(filt_format)-1] = '\0';
	    fs_give((void **) &combined);
	}

	/*
	 * Ad hoc attempt to make "Steve Hubert" match
	 * Steven Hubert but not Steven Shubert.
	 * We replace a <SPACE> with * <SPACE> (not * <SPACE> *).
	 */
	memset((void *)scp, 0, sizeof(scp));
	if(info->nosub)
	  strncpy(scp, string, sizeof(scp));
	else{
	    p = string;
	    q = scp;
	    while(*p && (q - scp) + 1 < sizeof(scp)){
		if(*p == SPACE && *(p+1) != SPACE){
		    *q++ = '*';
		    *q++ = *p++;
		}
		else
		  *q++ = *p++;
	    }
	}

	scp[sizeof(scp)-1] = '\0';

	slen = strlen(scp);
	flen = strlen(filt_format);
	/* truncate string if it will overflow filter */
	if(args*slen + flen - 2*args > sizeof(filter)-1)
	  scp[(sizeof(filter)-1 - flen)/args] = '\0';

	/*
	 * Replace %s's with scp.
	 */
	switch(args){
	  case 0:
	    snprintf(filter, sizeof(filter), "%s", filt_format);
	    break;
	  case 1:
	    snprintf(filter, sizeof(filter), filt_format, scp);
	    break;
	  case 2:
	    snprintf(filter, sizeof(filter), filt_format, scp, scp);
	    break;
	  case 3:
	    snprintf(filter, sizeof(filter), filt_format, scp, scp, scp);
	    break;
	  case 4:
	    snprintf(filter, sizeof(filter), filt_format, scp, scp, scp, scp);
	    break;
	  case 5:
	    snprintf(filter, sizeof(filter), filt_format, scp, scp, scp, scp, scp);
	    break;
	  case 6:
	    snprintf(filter, sizeof(filter), filt_format, scp, scp, scp, scp, scp, scp);
	    break;
	  case 7:
	    snprintf(filter, sizeof(filter), filt_format, scp, scp, scp, scp, scp, scp, scp);
	    break;
	  case 8:
	    snprintf(filter, sizeof(filter), filt_format, scp, scp, scp, scp, scp, scp, scp,
		    scp);
	    break;
	  case 9:
	    snprintf(filter, sizeof(filter), filt_format, scp, scp, scp, scp, scp, scp, scp,
		    scp, scp);
	    break;
	  case 10:
	  default:
	    snprintf(filter, sizeof(filter), filt_format, scp, scp, scp, scp, scp, scp, scp,
		    scp, scp, scp);
	    break;
	}

	/* replace double *'s with single *'s in filter */
	for(p = q = filter; *p; p++)
	  if(*p != '*' || p == filter || *(p-1) != '*')
	    *q++ = *p;

	*q = '\0';

	(void) removing_double_quotes(base);
	dprint((5, "about to ldap_search(\"%s\", %s)\n",
	       base ? base : "?", filter ? filter : "?"));
        if(ps_global->intr_pending)
	  srch_res = LDAP_PROTOCOL_ERROR;
	else{
	  int msgid;
	  time_t start_time;

	  start_time = time((time_t *)0);

	  dprint((6, "ldap_lookup: calling ldap_search\n"));
	  msgid = ldap_search(ld, base, info->scope, filter, NULL, 0);

	  if(msgid == -1)
	    srch_res = our_ldap_get_lderrno(ld, NULL, NULL);
	  else{
	    int lres;
	    /*
	     * Warning: struct timeval is not portable. However, since it is
	     * part of LDAP api it must be portable to all platforms LDAP
	     * has been ported to.
	     */
	    struct timeval t;

	    t.tv_sec  = 1; t.tv_usec = 0;
	      
	    do {
	      if(ps_global->intr_pending)
		intr_happened = 1;

	      dprint((6, "ldap_result(id=%d): ", msgid));
	      if((lres=ldap_result(ld, msgid, LDAP_MSG_ALL, &t, &res)) == -1){
	        /* error */
		srch_res = our_ldap_get_lderrno(ld, NULL, NULL);
	        dprint((6, "error (-1 returned): ld_errno=%d\n",
			   srch_res));
	      }
	      else if(lres == 0){  /* timeout, no results available */
		if(intr_happened){
		  ldap_abandon(ld, msgid);
		  srch_res = LDAP_PROTOCOL_ERROR;
		  if(our_ldap_get_lderrno(ld, NULL, NULL) == LDAP_SUCCESS)
		    our_ldap_set_lderrno(ld, LDAP_PROTOCOL_ERROR, NULL, NULL);

	          dprint((6, "timeout, intr: srch_res=%d\n",
			     srch_res));
		}
		else if(info->time > 0 &&
			((long)time((time_t *)0) - start_time) > info->time){
		  /* try for partial results */
		  t.tv_sec  = 0; t.tv_usec = 0;
		  lres = ldap_result(ld, msgid, LDAP_MSG_RECEIVED, &t, &res);
		  if(lres > 0 && lres != LDAP_RES_SEARCH_RESULT){
		    srch_res = LDAP_SUCCESS;
		    dprint((6, "partial result: lres=0x%x\n", lres));
		  }
		  else{
		    if(lres == 0)
		      ldap_abandon(ld, msgid);

		    srch_res = LDAP_TIMEOUT;
		    if(our_ldap_get_lderrno(ld, NULL, NULL) == LDAP_SUCCESS)
		      our_ldap_set_lderrno(ld, LDAP_TIMEOUT, NULL, NULL);

	            dprint((6,
			       "timeout, total_time (%d), srch_res=%d\n",
			       info->time, srch_res));
		  }
		}
		else{
	          dprint((6, "timeout\n"));
		}
	      }
	      else{
		srch_res = ldap_result2error(ld, res, 0);
	        dprint((6, "lres=0x%x, srch_res=%d\n", lres,
			   srch_res));
	      }
	    }while(lres == 0 &&
		    !(intr_happened ||
		      (info->time > 0 &&
		       ((long)time((time_t *)0) - start_time) > info->time)));
	  }
	}

	if(intr_happened){
	  wp_exit = 1;
          if(we_cancel)
            cancel_busy_cue(-1);

	  if(wp_err->error)
	    fs_give((void **)&wp_err->error);
	  else{
	    q_status_message(SM_ORDER, 0, 1, "Interrupt");
	    display_message('x');
	    fflush(stdout);
	  }

	  if(res)
	    ldap_msgfree(res);
	  if(ld)
	    ldap_unbind(ld);
	  
	  res = NULL; ld  = NULL;
	}
	else if(srch_res != LDAP_SUCCESS &&
	   srch_res != LDAP_TIMELIMIT_EXCEEDED &&
	   srch_res != LDAP_RESULTS_TOO_LARGE &&
	   srch_res != LDAP_TIMEOUT &&
	   srch_res != LDAP_SIZELIMIT_EXCEEDED){
	  wp_err->wp_err_occurred = 1;

	  ld_errnum = our_ldap_get_lderrno(ld, NULL, &ld_errstr);

	  snprintf(ebuf, sizeof(ebuf), _("LDAP search failed: %s%s%s%s"),
		  ldap_err2string(ld_errnum),
		  serv_errstr,
		  (ld_errstr && *ld_errstr) ? ": " : "",
		  (ld_errstr && *ld_errstr) ? ld_errstr : "");

          if(wp_err->error)
	    fs_give((void **)&wp_err->error);

          wp_err->error = cpystr(ebuf);
          if(we_cancel)
            cancel_busy_cue(-1);

          q_status_message(SM_ORDER, 3, 5, wp_err->error);
          display_message('x');
	  dprint((2, "%s\n", ebuf));
	  if(res)
	    ldap_msgfree(res);
	  if(ld)
	    ldap_unbind(ld);
	  
	  res = NULL; ld  = NULL;
	}
	else{
	  int cnt;

	  cnt = ldap_count_entries(ld, res);

	  if(cnt > 0){

	    if(srch_res == LDAP_TIMELIMIT_EXCEEDED ||
	       srch_res == LDAP_RESULTS_TOO_LARGE ||
	       srch_res == LDAP_TIMEOUT ||
	       srch_res == LDAP_SIZELIMIT_EXCEEDED){
	      wp_err->wp_err_occurred = 1;
	      ld_errnum = our_ldap_get_lderrno(ld, NULL, &ld_errstr);

	      snprintf(ebuf, sizeof(ebuf), _("LDAP partial results: %s%s%s%s"),
		      ldap_err2string(ld_errnum),
		      serv_errstr,
		      (ld_errstr && *ld_errstr) ? ": " : "",
		      (ld_errstr && *ld_errstr) ? ld_errstr : "");
	      dprint((2, "%s\n", ebuf));
	      if(wp_err->error)
		fs_give((void **)&wp_err->error);

	      wp_err->error = cpystr(ebuf);
	      if(we_cancel)
		cancel_busy_cue(-1);

	      q_status_message(SM_ORDER, 3, 5, wp_err->error);
	      display_message('x');
	    }

	    dprint((5, "Matched %d entries on %s\n",
	           cnt, serv ? serv : "?"));

	    serv_res = (LDAP_SERV_RES_S *)fs_get(sizeof(LDAP_SERV_RES_S));
	    memset((void *)serv_res, 0, sizeof(*serv_res));
	    serv_res->ld   = ld;
	    serv_res->res  = res;
	    serv_res->info_used = copy_ldap_serv_info(info);
	    /* Save by reference? */
	    if(info->ref){
		snprintf(buf, sizeof(buf), "%s:%s", serv, comatose(info->port));
		serv_res->serv = cpystr(buf);
	    }
	    else
	      serv_res->serv = NULL;

	    serv_res->next = NULL;
	  }
	  else{
	    if(srch_res == LDAP_TIMELIMIT_EXCEEDED ||
	       srch_res == LDAP_RESULTS_TOO_LARGE ||
	       srch_res == LDAP_TIMEOUT ||
	       srch_res == LDAP_SIZELIMIT_EXCEEDED){
	      wp_err->wp_err_occurred = 1;
	      wp_err->ldap_errno      = srch_res;

	      ld_errnum = our_ldap_get_lderrno(ld, NULL, &ld_errstr);

	      snprintf(ebuf, sizeof(ebuf), _("LDAP search failed: %s%s%s%s"),
		      ldap_err2string(ld_errnum),
		      serv_errstr,
		      (ld_errstr && *ld_errstr) ? ": " : "",
		      (ld_errstr && *ld_errstr) ? ld_errstr : "");

	      if(wp_err->error)
		fs_give((void **)&wp_err->error);

	      wp_err->error = cpystr(ebuf);
	      if(we_cancel)
		cancel_busy_cue(-1);

	      q_status_message(SM_ORDER, 3, 5, wp_err->error);
	      display_message('x');
	      dprint((2, "%s\n", ebuf));
	    }

	    dprint((5, "Matched 0 entries on %s\n",
		   serv ? serv : "?"));
	    if(res)
	      ldap_msgfree(res);
	    if(ld)
	      ldap_unbind(ld);

	    res = NULL; ld  = NULL;
	  }
	}
      }
    }

    if(we_cancel)
      cancel_busy_cue(-1);

    if(we_turned_on)
      intr_handling_off();

    if(serv)
      fs_give((void **)&serv);
    if(base)
      fs_give((void **)&base);
    if(serv_errstr)
      fs_give((void **)&serv_errstr);

    return(serv_res);
}
static LDAP *
open_ldap_connection(const char *ldapServer, int port)
{
    LDAP *ld = NULL;
#if HAS_URI_SUPPORT
    if (strstr(ldapServer, "://") != NULL) {
	int rc = ldap_initialize(&ld, ldapServer);
	if (rc != LDAP_SUCCESS) {
	    fprintf(stderr, "\nUnable to connect to LDAPURI:%s\n", ldapServer);
	    exit(1);
	}
    } else
#endif
#if NETSCAPE_SSL
    if (sslpath) {
	if (!sslinit && (ldapssl_client_init(sslpath, NULL) != LDAP_SUCCESS)) {
	    fprintf(stderr, "\nUnable to initialise SSL with cert path %s\n",
		sslpath);
	    exit(1);
	} else {
	    sslinit++;
	}
	if ((ld = ldapssl_init(ldapServer, port, 1)) == NULL) {
	    fprintf(stderr, "\nUnable to connect to SSL LDAP server: %s port:%d\n",
		ldapServer, port);
	    exit(1);
	}
    } else
#endif
    if ((ld = ldap_init(ldapServer, port)) == NULL) {
	fprintf(stderr, "\nUnable to connect to LDAP server:%s port:%d\n",
	    ldapServer, port);
	exit(1);
    }
    if (connect_timeout)
	squid_ldap_set_connect_timeout(ld, connect_timeout);

#ifdef LDAP_VERSION3
    if (version == -1) {
	version = LDAP_VERSION2;
    }
    if (ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &version) != LDAP_SUCCESS) {
	fprintf(stderr, "Could not set LDAP_OPT_PROTOCOL_VERSION %d\n",
	    version);
	exit(1);
    }
    if (use_tls) {
#ifdef LDAP_OPT_X_TLS
	if (version != LDAP_VERSION3) {
	    fprintf(stderr, "TLS requires LDAP version 3\n");
	    exit(1);
	} else if (ldap_start_tls_s(ld, NULL, NULL) != LDAP_SUCCESS) {
	    fprintf(stderr, "Could not Activate TLS connection\n");
	    exit(1);
	}
#else
	fprintf(stderr, "TLS not supported with your LDAP library\n");
	exit(1);
#endif
    }
#endif
    squid_ldap_set_timelimit(ld, timelimit);
    squid_ldap_set_referrals(ld, !noreferrals);
    squid_ldap_set_aliasderef(ld, aliasderef);
    return ld;
}