[PATCH] dirmngr_ldap: support ldap secure connection(ldaps)

Dmitry Falko dfalko at digiflak.com
Wed May 20 15:27:11 CEST 2015


Hello!

I encountered a problem connecting to the LDAP server via TLS and wrote 
a small patch, send it as is.

* dirmngr.h (ldap_server_s): add schema field
* dirmngr_ldap.c (fetch_ldap): ldaps support
* ldap.c (make_url, start_cert_fetch_ldap): add schema
* ldapserver.c (ldapserver_parse_one): parse schema
* server.c (lookup_cert_by_pattern): additional log info

dirmngr_ldap can retrieve certificates from LDAP server
by TLS(using ldaps protocol). Protocol can be set in
dirmngr_ldapserver.conf:
hostname:port:username:password:base_dn:schema
If not set use ldap.By default dirmngr_ldap use
/etc/ssl/CA(dirmngr_ldap.c CA_CERT_DEFAULT) CA certificate,
user can set DIRMNGR_LDAP_CACERT env variable to
override this value.
---
  dirmngr/dirmngr.h      |  1 +
  dirmngr/dirmngr_ldap.c | 61 
+++++++++++++++++++++++++++++++++++++++++++++-----
  dirmngr/ldap.c         | 24 +++++++++++++++-----
  dirmngr/ldapserver.c   |  5 +++++
  dirmngr/server.c       |  3 ++-
  5 files changed, 81 insertions(+), 13 deletions(-)

diff --git a/dirmngr/dirmngr.h b/dirmngr/dirmngr.h
index 4f037e7..3406494 100644
--- a/dirmngr/dirmngr.h
+++ b/dirmngr/dirmngr.h
@@ -46,6 +46,7 @@ struct ldap_server_s
    char *user;
    char *pass;
    char *base;
+  char *schema;
  };
  typedef struct ldap_server_s *ldap_server_t;

diff --git a/dirmngr/dirmngr_ldap.c b/dirmngr/dirmngr_ldap.c
index 61a7e39..8bb739c 100644
--- a/dirmngr/dirmngr_ldap.c
+++ b/dirmngr/dirmngr_ldap.c
@@ -46,6 +46,8 @@
    /* For OpenLDAP, to enable the API that we're using. */
  # define LDAP_DEPRECATED 1
  # include <ldap.h>
+  /* FIXME: use configure script to set this define */
+# define CA_CERT_DEFAULT ("/etc/ssl/CA")
  #endif


@@ -571,9 +573,10 @@ fetch_ldap (my_opt_t myopt, const char *url, const 
LDAPURLDesc *ludp)
    LDAP *ld;
    LDAPMessage *msg;
    int rc = 0;
-  char *host, *dn, *filter, *attrs[2], *attr;
+  char *host, *dn, *filter, *attrs[2], *attr, *ca_cert, *ldap_url;
    int port;
    int ret;
+  int err;

    host     = myopt->host?   myopt->host   : ludp->lud_host;
    port     = myopt->port?   myopt->port   : ludp->lud_port;
@@ -583,6 +586,17 @@ fetch_ldap (my_opt_t myopt, const char *url, const 
LDAPURLDesc *ludp)
    attrs[1] = NULL;
    attr = attrs[0];

+  ca_cert = getenv("DIRMNGR_LDAP_CACERT");
+  if(!ca_cert)
+    {
+      if (myopt->verbose)
+        {
+          log_info("Using default CA certificate");
+        }
+
+      ca_cert = CA_CERT_DEFAULT;
+    }
+
    if (!port)
      port = (ludp->lud_scheme && !strcmp (ludp->lud_scheme, "ldaps"))? 
636:389;

@@ -628,23 +642,58 @@ fetch_ldap (my_opt_t myopt, const char *url, const 
LDAPURLDesc *ludp)


    set_timeout (myopt);
+
+  ldap_url = alloca(4 + strlen(ludp->lud_scheme)
+                  + strlen(host)
+                  + 5); /* for port */
+  sprintf(ldap_url, "%s://%s:%d", ludp->lud_scheme, host, port);
+
    npth_unprotect ();
-  ld = my_ldap_init (host, port);
+  err = ldap_initialize(&ld, ldap_url) ;
    npth_protect ();
-  if (!ld)
+  if (err != LDAP_SUCCESS)
      {
-      log_error (_("LDAP init to '%s:%d' failed: %s\n"),
-                 host, port, strerror (errno));
+      log_error (_("LDAP init to '%s' failed: %s\n"),
+                 ldap_url, ldap_err2string (errno));
        return -1;
      }
    npth_unprotect ();
+
+  if(!strcmp (ludp->lud_scheme, "ldaps"))
+    {
+      /* Additional options for tls connection */
+      /*FIXME: LDAP_OPT_X_TLS_NEVER or LDAP_OPT_X_TLS_HARD, add option*/
+      int req_cert = LDAP_OPT_X_TLS_NEVER;
+
+      err = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE,
+                                ca_cert);
+      npth_protect ();
+      if(err != LDAP_SUCCESS)
+        {
+          log_error (_("setting ca-certificate failed: %s\n"),
+                 ldap_err2string (err));
+          return -1;
+        }
+      npth_unprotect ();
+      err=ldap_set_option(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT,
+                                &req_cert);
+      npth_protect ();
+      if(err != LDAP_SUCCESS)
+        {
+          log_error (_("setting require certificate failed: %s\n"),
+                ldap_err2string (err));
+          return -1;
+        }
+      npth_unprotect ();
+    }
+
    /* Fixme:  Can we use MYOPT->user or is it shared with other 
theeads?.  */
    ret = my_ldap_simple_bind_s (ld, myopt->user, myopt->pass);
    npth_protect ();
    if (ret)
      {
        log_error (_("binding to '%s:%d' failed: %s\n"),
-                 host, port, strerror (errno));
+                 host, port, ldap_err2string (errno));
        ldap_unbind (ld);
        return -1;
      }
diff --git a/dirmngr/ldap.c b/dirmngr/ldap.c
index e4c6aa2..d4e0730 100644
--- a/dirmngr/ldap.c
+++ b/dirmngr/ldap.c
@@ -423,10 +423,10 @@ escape4url (const char *string)
     need the host and port because this will be specified using the
     override options. */
  static gpg_error_t
-make_url (char **url, const char *dn, const char *filter)
+make_url (char **url, const char *dn, const char *filter, const char 
*schema)
  {
    gpg_error_t err;
-  char *u_dn, *u_filter;
+  char *u_dn, *u_filter, *u_schema;
    char const attrs[] = (USERCERTIFICATE ","
  /*                         USERSMIMECERTIFICATE "," */
                          CACERTIFICATE ","
@@ -434,6 +434,10 @@ make_url (char **url, const char *dn, const char 
*filter)

    *url = NULL;

+  u_schema = escape4url (schema);
+  if(!u_schema)
+    return gpg_error_from_errno (errno);
+
    u_dn = escape4url (dn);
    if (!u_dn)
        return gpg_error_from_errno (errno);
@@ -445,7 +449,8 @@ make_url (char **url, const char *dn, const char 
*filter)
        xfree (u_dn);
        return err;
      }
-  *url = malloc ( 8 + strlen (u_dn)
+  *url = malloc ( 4 + strlen (schema)
+                     + strlen (u_dn)
                   + 1 + strlen (attrs)
                   + 5 + strlen (u_filter) + 1 );
    if (!*url)
@@ -456,12 +461,14 @@ make_url (char **url, const char *dn, const char 
*filter)
        return err;
      }

-  stpcpy (stpcpy (stpcpy (stpcpy (stpcpy (stpcpy (*url, "ldap:///"),
+  stpcpy (stpcpy (stpcpy (stpcpy (stpcpy (stpcpy (stpcpy(*url, u_schema),
+                                                  ":///"),
                                            u_dn),
                                    "?"),
                            attrs),
                    "?sub?"),
            u_filter);
+  xfree (u_schema);
    xfree (u_dn);
    xfree (u_filter);
    return 0;
@@ -525,6 +532,7 @@ start_cert_fetch_ldap (ctrl_t ctrl, 
cert_fetch_context_t *context,
    const char *user;
    const char *pass;
    const char *base;
+  const char *schema;
    const char *argv[50];
    int argc;
    char portbuf[30], timeoutbuf[30];
@@ -538,6 +546,7 @@ start_cert_fetch_ldap (ctrl_t ctrl, 
cert_fetch_context_t *context,
        user = server->user;
        pass = server->pass;
        base = server->base;
+      schema = server->schema;
      }
    else /* Use a default server. */
      return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
@@ -545,6 +554,9 @@ start_cert_fetch_ldap (ctrl_t ctrl, 
cert_fetch_context_t *context,
    if (!base)
      base = "";

+  if(!schema)
+    schema = "ldap";
+
    argc = 0;
    if (pass) /* Note: Must be the first item. */
      {
@@ -606,9 +618,9 @@ start_cert_fetch_ldap (ctrl_t ctrl, 
cert_fetch_context_t *context,
            return gpg_error (GPG_ERR_INV_USER_ID);
          }
        if ((sl->flags & 1))
-        err = make_url (&url, sl->d, "objectClass=*");
+        err = make_url (&url, sl->d, "objectClass=*", schema);
        else
-        err = make_url (&url, base, sl->d);
+        err = make_url (&url, base, sl->d, schema);
        free_strlist (sl);
        if (err)
          {
diff --git a/dirmngr/ldapserver.c b/dirmngr/ldapserver.c
index 16e13e2..87c8b47 100644
--- a/dirmngr/ldapserver.c
+++ b/dirmngr/ldapserver.c
@@ -115,6 +115,11 @@ ldapserver_parse_one (char *line,
          server->base = xstrdup (p);
        break;

+  case 6:
+    if (*p)
+      server->schema = xstrdup (p);
+    break;
+
      default:
        /* (We silently ignore extra fields.) */
        break;
diff --git a/dirmngr/server.c b/dirmngr/server.c
index 1b7e9e9..bcf83f9 100644
--- a/dirmngr/server.c
+++ b/dirmngr/server.c
@@ -1259,7 +1259,8 @@ lookup_cert_by_pattern (assuan_context_t ctx, char 
*line,
        ldap_server_t ldapserver = ldapserver_iter.server;

        if (DBG_LOOKUP)
-        log_debug ("cmd_lookup: trying %s:%d base=%s\n",
+        log_debug ("cmd_lookup: trying %s://%s:%d base=%s\n",
+                   ldapserver->schema ? ldapserver->schema: "ldap",
                     ldapserver->host, ldapserver->port,
                     ldapserver->base?ldapserver->base : "[default]");

-- 
1.9.1


-- 
Best Regards!

-------------- next part --------------
An HTML attachment was scrubbed...
URL: </pipermail/attachments/20150520/5c087749/attachment-0001.html>


More information about the Gnupg-devel mailing list