aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--dirmngr/dirmngr.h4
-rw-r--r--dirmngr/ks-action.c52
-rw-r--r--dirmngr/ks-engine-ldap.c294
-rw-r--r--dirmngr/ldap.c2
-rw-r--r--dirmngr/ldapserver.c122
-rw-r--r--dirmngr/ldapserver.h12
-rw-r--r--dirmngr/server.c49
7 files changed, 367 insertions, 168 deletions
diff --git a/dirmngr/dirmngr.h b/dirmngr/dirmngr.h
index 92d9d4b6a..498a3d7b1 100644
--- a/dirmngr/dirmngr.h
+++ b/dirmngr/dirmngr.h
@@ -50,7 +50,9 @@ struct ldap_server_s
char *user;
char *pass;
char *base;
- unsigned int use_ldaps:1;
+ unsigned int starttls:1; /* Use STARTTLS. */
+ unsigned int ldap_over_tls:1; /* Use LDAP over an TLS tunnel */
+ unsigned int ntds:1; /* Use Active Directory authentication. */
};
typedef struct ldap_server_s *ldap_server_t;
diff --git a/dirmngr/ks-action.c b/dirmngr/ks-action.c
index 5c097754e..57cf04a7e 100644
--- a/dirmngr/ks-action.c
+++ b/dirmngr/ks-action.c
@@ -67,6 +67,8 @@ ks_action_help (ctrl_t ctrl, const char *url)
{
gpg_error_t err;
parsed_uri_t parsed_uri; /* The broken down URI. */
+ char *tmpstr;
+ const char *s;
if (!url || !*url)
{
@@ -76,7 +78,34 @@ ks_action_help (ctrl_t ctrl, const char *url)
else
{
#if USE_LDAP
- if (ldap_uri_p (url))
+ if (!strncmp (url, "ldap:", 5) && !(url[5] == '/' && url[6] == '/'))
+ {
+ /* Special ldap scheme given. This differs from a valid
+ * ldap scheme in that no double slash follows. Use
+ * http_parse_uri to put it as opaque value into parsed_uri. */
+ tmpstr = strconcat ("opaque:", url+5, NULL);
+ if (!tmpstr)
+ err = gpg_error_from_syserror ();
+ else
+ {
+ err = http_parse_uri (&parsed_uri, tmpstr, 0);
+ xfree (tmpstr);
+ }
+ }
+ else if ((s=strchr (url, ':')) && !(s[1] == '/' && s[2] == '/'))
+ {
+ /* No scheme given. Use http_parse_uri to put the string as
+ * opaque value into parsed_uri. */
+ tmpstr = strconcat ("opaque:", url, NULL);
+ if (!tmpstr)
+ err = gpg_error_from_syserror ();
+ else
+ {
+ err = http_parse_uri (&parsed_uri, tmpstr, 0);
+ xfree (tmpstr);
+ }
+ }
+ else if (ldap_uri_p (url))
err = ldap_parse_uri (&parsed_uri, url);
else
#endif
@@ -164,9 +193,10 @@ ks_action_search (ctrl_t ctrl, uri_item_t keyservers,
int is_ldap = 0;
unsigned int http_status = 0;
#if USE_LDAP
- is_ldap = (strcmp (uri->parsed_uri->scheme, "ldap") == 0
- || strcmp (uri->parsed_uri->scheme, "ldaps") == 0
- || strcmp (uri->parsed_uri->scheme, "ldapi") == 0);
+ is_ldap = (!strcmp (uri->parsed_uri->scheme, "ldap")
+ || !strcmp (uri->parsed_uri->scheme, "ldaps")
+ || !strcmp (uri->parsed_uri->scheme, "ldapi")
+ || uri->parsed_uri->opaque);
#endif
if (is_http || is_ldap)
{
@@ -242,9 +272,10 @@ ks_action_get (ctrl_t ctrl, uri_item_t keyservers,
is_hkp_s = is_http_s = 0;
#if USE_LDAP
- is_ldap = (strcmp (uri->parsed_uri->scheme, "ldap") == 0
- || strcmp (uri->parsed_uri->scheme, "ldaps") == 0
- || strcmp (uri->parsed_uri->scheme, "ldapi") == 0);
+ is_ldap = (!strcmp (uri->parsed_uri->scheme, "ldap")
+ || !strcmp (uri->parsed_uri->scheme, "ldaps")
+ || !strcmp (uri->parsed_uri->scheme, "ldapi")
+ || uri->parsed_uri->opaque);
#endif
if (is_hkp_s || is_http_s || is_ldap)
@@ -382,9 +413,10 @@ ks_action_put (ctrl_t ctrl, uri_item_t keyservers,
int is_ldap = 0;
#if USE_LDAP
- is_ldap = (strcmp (uri->parsed_uri->scheme, "ldap") == 0
- || strcmp (uri->parsed_uri->scheme, "ldaps") == 0
- || strcmp (uri->parsed_uri->scheme, "ldapi") == 0);
+ is_ldap = (!strcmp (uri->parsed_uri->scheme, "ldap")
+ || !strcmp (uri->parsed_uri->scheme, "ldaps")
+ || !strcmp (uri->parsed_uri->scheme, "ldapi")
+ || uri->parsed_uri->opaque);
#endif
if (is_http || is_ldap)
diff --git a/dirmngr/ks-engine-ldap.c b/dirmngr/ks-engine-ldap.c
index b7ff0633c..1b5c2ca32 100644
--- a/dirmngr/ks-engine-ldap.c
+++ b/dirmngr/ks-engine-ldap.c
@@ -50,6 +50,7 @@
#include "../common/mbox-util.h"
#include "ks-engine.h"
#include "ldap-parse-uri.h"
+#include "ldapserver.h"
/* Flags with infos from the connected server. */
@@ -312,11 +313,11 @@ ks_ldap_help (ctrl_t ctrl, parsed_uri_t uri)
{
const char data[] =
"Handler for LDAP URLs:\n"
- " ldap://host:port/[BASEDN]???[bindname=BINDNAME,password=PASSWORD]\n"
+ " ldap://HOST:PORT/[BASEDN]???[bindname=BINDNAME,password=PASSWORD]\n"
"\n"
"Note: basedn, bindname and password need to be percent escaped. In\n"
"particular, spaces need to be replaced with %20 and commas with %2c.\n"
- "bindname will typically be of the form:\n"
+ "Thus bindname will typically be of the form:\n"
"\n"
" uid=user%2cou=PGP%20Users%2cdc=EXAMPLE%2cdc=ORG\n"
"\n"
@@ -324,12 +325,19 @@ ks_ldap_help (ctrl_t ctrl, parsed_uri_t uri)
"then the server's certificate will be checked. If it is not valid, any\n"
"operation will be aborted. Note that ldaps means LDAP with STARTTLS\n"
"\n"
+ "As an alternative to an URL a string in this form may be used:\n"
+ "\n"
+ " HOST:PORT:BINDNAME:PASSWORD:BASEDN:FLAGS:\n"
+ "\n"
+ "The use of the percent sign or a colon in one of the string values is\n"
+ "currently not supported.\n"
+ "\n"
"Supported methods: search, get, put\n";
gpg_error_t err;
if(!uri)
err = ks_print_help (ctrl, " ldap");
- else if (uri->is_ldap)
+ else if (uri->is_ldap || uri->opaque)
err = ks_print_help (ctrl, data);
else
err = 0;
@@ -491,96 +499,164 @@ keyspec_to_ldap_filter (const char *keyspec, char **filter, int only_exact,
If no LDAP error occurred, you still need to check that *basednp is
valid. If it is NULL, then the server does not appear to be an
OpenPGP Keyserver. */
-static int
+static gpg_error_t
my_ldap_connect (parsed_uri_t uri, LDAP **ldap_connp,
- char **basednp, unsigned int *r_serverinfo)
+ char **r_basedn, char **r_host, int *r_use_tls,
+ unsigned int *r_serverinfo)
{
- int err = 0;
+ gpg_error_t err = 0;
+ int lerr;
+ ldap_server_t server = NULL;
LDAP *ldap_conn = NULL;
- char *user = uri->auth;
- struct uri_tuple_s *password_param;
- char *password;
char *basedn = NULL;
-
+ char *host = NULL; /* Host to use. */
+ int port; /* Port to use. */
+ int use_tls; /* 1 = starttls, 2 = ldap-over-tls */
+ int use_ntds; /* Use Active Directory authentication. */
+ const char *bindname;
+ const char *password;
+ const char *basedn_arg;
+ char *tmpstr;
+
+ if (r_basedn)
+ *r_basedn = NULL;
+ if (r_host)
+ *r_host = NULL;
+ if (r_use_tls)
+ *r_use_tls = 0;
*r_serverinfo = 0;
- password_param = uri_query_lookup (uri, "password");
- password = password_param ? password_param->value : NULL;
+ if (uri->opaque)
+ {
+ server = ldapserver_parse_one (uri->path, NULL, 0);
+ if (!server)
+ return gpg_error (GPG_ERR_LDAP_OTHER);
+ host = server->host;
+ port = server->port;
+ bindname = server->user;
+ password = bindname? server->pass : NULL;
+ basedn_arg = server->base;
+ use_tls = server->starttls? 1 : server->ldap_over_tls? 2 : 0;
+ use_ntds = server->ntds;
+ }
+ else
+ {
+ struct uri_tuple_s *password_param;
+
+ password_param = uri_query_lookup (uri, "password");
+ password = password_param ? password_param->value : NULL;
+
+ host = uri->host;
+ port = uri->port;
+ bindname = uri->auth;
+ password = bindname? uri_query_value (uri, "password") : NULL;
+ basedn_arg = uri->path;
+ use_tls = uri->use_tls ? 1 : 0;
+ use_ntds = uri->ad_current;
+ }
+
+ if (!port)
+ port = use_tls == 2? 636 : 389;
+
+
+ if (host)
+ {
+ host = xtrystrdup (host);
+ if (!host)
+ {
+ err = gpg_error_from_syserror ();
+ goto out;
+ }
+ }
if (opt.debug)
- log_debug ("my_ldap_connect(%s:%d/%s????%s%s%s%s%s%s)\n",
- uri->host, uri->port,
- uri->path ? uri->path : "",
- uri->auth ? "bindname=" : "",
- uri->auth ? uri->auth : "",
- uri->auth && password ? "," : "",
- password ? "password=" : "",
- password ? ">not shown<": "",
- uri->ad_current? " auth=>current_user<":"");
+ log_debug ("my_ldap_connect(%s:%d/%s????%s%s%s%s%s)\n",
+ host, port,
+ basedn_arg ? basedn_arg : "",
+ bindname ? "bindname=" : "",
+ bindname ? bindname : "",
+ password ? "," : "",
+ password ? "password=>not_shown<" : "",
+ use_ntds ? " auth=>current_user<":"");
+
/* If the uri specifies a secure connection and we don't support
TLS, then fail; don't silently revert to an insecure
connection. */
- if (uri->use_tls)
+ if (use_tls)
{
#ifndef HAVE_LDAP_START_TLS_S
- log_error ("Can't use LDAP to connect to the server: no TLS support.");
+ log_error ("ldap: can't connect to the server: no TLS support.");
err = GPG_ERR_LDAP_NOT_SUPPORTED;
goto out;
#endif
}
- ldap_conn = ldap_init (uri->host, uri->port);
+
+#ifdef HAVE_W32_SYSTEM
+ npth_unprotect ();
+ ldap_conn = ldap_sslinit (host, port, (use_tls == 2));
+ npth_protect ();
if (!ldap_conn)
{
- err = gpg_err_code_from_syserror ();
- log_error ("error initializing LDAP for (%s://%s:%d)\n",
- uri->scheme, uri->host, uri->port);
+ lerr = LdapGetLastError ();
+ err = ldap_err_to_gpg_err (lerr);
+ log_error ("error initializing LDAP '%s:%d': %s\n",
+ host, port, ldap_err2string (lerr));
goto out;
}
+#else /* Unix */
+ tmpstr = xtryasprintf ("%s://%s:%d",
+ use_tls == 2? "ldaps" : "ldap",
+ host, port);
+ if (!tmpstr)
+ {
+ err = gpg_error_from_syserror ();
+ goto out;
+ }
+ npth_unprotect ();
+ lerr = ldap_initialize (&ldap_conn, tmpstr);
+ npth_protect ();
+ if (lerr || !ldap_conn)
+ {
+ err = ldap_err_to_gpg_err (lerr);
+ log_error ("error initializing LDAP '%s': %s\n",
+ tmpstr, ldap_err2string (lerr));
+ xfree (tmpstr);
+ goto out;
+ }
+ xfree (tmpstr);
+#endif /* Unix */
#ifdef HAVE_LDAP_SET_OPTION
{
int ver = LDAP_VERSION3;
- err = ldap_set_option (ldap_conn, LDAP_OPT_PROTOCOL_VERSION, &ver);
- if (err != LDAP_SUCCESS)
+ lerr = ldap_set_option (ldap_conn, LDAP_OPT_PROTOCOL_VERSION, &ver);
+ if (lerr != LDAP_SUCCESS)
{
log_error ("ks-ldap: unable to go to LDAP 3: %s\n",
- ldap_err2string (err));
+ ldap_err2string (lerr));
+ err = ldap_err_to_gpg_err (lerr);
goto out;
}
}
#endif
- /* XXX: It would be nice to have an option to provide the server's
- certificate. */
-#if 0
-#if defined(LDAP_OPT_X_TLS_CACERTFILE) && defined(HAVE_LDAP_SET_OPTION)
- err = ldap_set_option (NULL, LDAP_OPT_X_TLS_CACERTFILE, ca_cert_file);
- if (err)
- {
- log_error ("unable to set ca-cert-file to '%s': %s\n",
- ca_cert_file, ldap_err2string (err));
- goto out;
- }
-#endif /* LDAP_OPT_X_TLS_CACERTFILE && HAVE_LDAP_SET_OPTION */
-#endif
#ifdef HAVE_LDAP_START_TLS_S
- if (uri->use_tls)
+ if (use_tls == 1)
{
- /* XXX: We need an option to determine whether to abort if the
- certificate is bad or not. Right now we conservatively
- default to checking the certificate and aborting. */
#ifndef HAVE_W32_SYSTEM
int check_cert = LDAP_OPT_X_TLS_HARD; /* LDAP_OPT_X_TLS_NEVER */
- err = ldap_set_option (ldap_conn,
- LDAP_OPT_X_TLS_REQUIRE_CERT, &check_cert);
- if (err)
+ lerr = ldap_set_option (ldap_conn,
+ LDAP_OPT_X_TLS_REQUIRE_CERT, &check_cert);
+ if (lerr)
{
- log_error ("error setting TLS option on LDAP connection\n");
+ log_error ("ldap: error setting an TLS option: %s\n",
+ ldap_err2string (lerr));
+ err = ldap_err_to_gpg_err (lerr);
goto out;
}
#else
@@ -592,7 +668,7 @@ my_ldap_connect (parsed_uri_t uri, LDAP **ldap_connp,
#endif
npth_unprotect ();
- err = ldap_start_tls_s (ldap_conn,
+ lerr = ldap_start_tls_s (ldap_conn,
#ifdef HAVE_W32_SYSTEM
/* ServerReturnValue, result */
NULL, NULL,
@@ -600,26 +676,29 @@ my_ldap_connect (parsed_uri_t uri, LDAP **ldap_connp,
/* ServerControls, ClientControls */
NULL, NULL);
npth_protect ();
- if (err)
+ if (lerr)
{
- log_error ("error connecting to LDAP server with TLS\n");
+ log_error ("ldap: error switching to STARTTLS mode: %s\n",
+ ldap_err2string (lerr));
+ err = ldap_err_to_gpg_err (lerr);
goto out;
}
}
#endif
- if (uri->ad_current)
+ if (use_ntds)
{
if (opt.debug)
- log_debug ("LDAP bind to current user via AD\n");
+ log_debug ("ldap: binding to current user via AD\n");
#ifdef HAVE_W32_SYSTEM
npth_unprotect ();
- err = ldap_bind_s (ldap_conn, NULL, NULL, LDAP_AUTH_NEGOTIATE);
+ lerr = ldap_bind_s (ldap_conn, NULL, NULL, LDAP_AUTH_NEGOTIATE);
npth_protect ();
- if (err != LDAP_SUCCESS)
+ if (lerr != LDAP_SUCCESS)
{
log_error ("error binding to LDAP via AD: %s\n",
- ldap_err2string (err));
+ ldap_err2string (lerr));
+ err = ldap_err_to_gpg_err (lerr);
goto out;
}
#else
@@ -627,18 +706,19 @@ my_ldap_connect (parsed_uri_t uri, LDAP **ldap_connp,
goto out;
#endif
}
- else if (uri->auth)
+ else if (bindname)
{
if (opt.debug)
- log_debug ("LDAP bind to %s, password %s\n",
- user, password ? ">not shown<" : ">none<");
+ log_debug ("LDAP bind to '%s', password '%s'\n",
+ bindname, password ? ">not_shown<" : ">none<");
npth_unprotect ();
- err = ldap_simple_bind_s (ldap_conn, user, password);
+ lerr = ldap_simple_bind_s (ldap_conn, bindname, password);
npth_protect ();
- if (err != LDAP_SUCCESS)
+ if (lerr != LDAP_SUCCESS)
{
- log_error ("error binding to LDAP: %s\n", ldap_err2string (err));
+ log_error ("error binding to LDAP: %s\n", ldap_err2string (lerr));
+ err = ldap_err_to_gpg_err (lerr);
goto out;
}
}
@@ -647,13 +727,16 @@ my_ldap_connect (parsed_uri_t uri, LDAP **ldap_connp,
/* By default we don't bind as there is usually no need to. */
}
- if (uri->path && *uri->path)
+ if (basedn_arg && *basedn_arg)
{
- /* User specified base DN. */
- basedn = xstrdup (uri->path);
-
- /* If the user specifies a base DN, then we know the server is a
+ /* User specified base DN. In this case we know the server is a
* real LDAP server. */
+ basedn = xtrystrdup (basedn_arg);
+ if (!basedn)
+ {
+ err = gpg_error_from_syserror ();
+ goto out;
+ }
*r_serverinfo |= SERVERINFO_REALLDAP;
}
else
@@ -662,11 +745,11 @@ my_ldap_connect (parsed_uri_t uri, LDAP **ldap_connp,
char *attr[] = { "namingContexts", NULL };
npth_unprotect ();
- err = ldap_search_s (ldap_conn, "", LDAP_SCOPE_BASE,
+ lerr = ldap_search_s (ldap_conn, "", LDAP_SCOPE_BASE,
"(objectClass=*)", attr, 0, &res);
npth_protect ();
- if (err == LDAP_SUCCESS)
+ if (lerr == LDAP_SUCCESS)
{
char **context;
@@ -685,7 +768,7 @@ my_ldap_connect (parsed_uri_t uri, LDAP **ldap_connp,
*r_serverinfo |= SERVERINFO_REALLDAP;
- for (i = 0; context[i] && ! basedn; i++)
+ for (i = 0; context[i] && !basedn; i++)
{
char **vals;
LDAPMessage *si_res;
@@ -695,13 +778,13 @@ my_ldap_connect (parsed_uri_t uri, LDAP **ldap_connp,
char *object = xasprintf ("cn=pgpServerInfo,%s",
context[i]);
npth_unprotect ();
- err = ldap_search_s (ldap_conn, object, LDAP_SCOPE_BASE,
+ lerr = ldap_search_s (ldap_conn, object, LDAP_SCOPE_BASE,
"(objectClass=*)", attr2, 0, &si_res);
npth_protect ();
xfree (object);
}
- if (err == LDAP_SUCCESS)
+ if (lerr == LDAP_SUCCESS)
{
vals = ldap_get_values (ldap_conn, si_res,
"pgpBaseKeySpaceDN");
@@ -754,7 +837,7 @@ my_ldap_connect (parsed_uri_t uri, LDAP **ldap_connp,
ldap_value_free (context);
}
}
- else
+ else /* ldap_search failed. */
{
/* We don't have an answer yet, which means the server might
be a PGP.com keyserver. */
@@ -764,10 +847,10 @@ my_ldap_connect (parsed_uri_t uri, LDAP **ldap_connp,
char *attr2[] = { "pgpBaseKeySpaceDN", "version", "software", NULL };
npth_unprotect ();
- err = ldap_search_s (ldap_conn, "cn=pgpServerInfo", LDAP_SCOPE_BASE,
+ lerr = ldap_search_s (ldap_conn, "cn=pgpServerInfo", LDAP_SCOPE_BASE,
"(objectClass=*)", attr2, 0, &si_res);
npth_protect ();
- if (err == LDAP_SUCCESS)
+ if (lerr == LDAP_SUCCESS)
{
/* For the PGP LDAP keyserver, this is always
* "OU=ACTIVE,O=PGP KEYSPACE,C=US", but it might not be
@@ -827,23 +910,27 @@ my_ldap_connect (parsed_uri_t uri, LDAP **ldap_connp,
(*r_serverinfo & SERVERINFO_PGPKEYV2)? "pgpKeyV2":"pgpKey");
}
- if (err)
- xfree (basedn);
- else
- {
- if (basednp)
- *basednp = basedn;
- else
- xfree (basedn);
- }
+ ldapserver_list_free (server);
if (err)
{
+ xfree (basedn);
if (ldap_conn)
ldap_unbind (ldap_conn);
}
else
- *ldap_connp = ldap_conn;
+ {
+ if (r_basedn)
+ *r_basedn = basedn;
+ else
+ xfree (basedn);
+ if (r_host)
+ *r_host = host;
+ else
+ xfree (host);
+
+ *ldap_connp = ldap_conn;
+ }
return err;
}
@@ -944,6 +1031,8 @@ ks_ldap_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec,
gpg_error_t err = 0;
int ldap_err;
unsigned int serverinfo;
+ char *host = NULL;
+ int use_tls;
char *filter = NULL;
LDAP *ldap_conn = NULL;
char *basedn = NULL;
@@ -960,12 +1049,11 @@ ks_ldap_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec,
}
/* Make sure we are talking to an OpenPGP LDAP server. */
- ldap_err = my_ldap_connect (uri, &ldap_conn, &basedn, &serverinfo);
- if (ldap_err || !basedn)
+ err = my_ldap_connect (uri, &ldap_conn,
+ &basedn, &host, &use_tls, &serverinfo);
+ if (err || !basedn)
{
- if (ldap_err)
- err = ldap_err_to_gpg_err (ldap_err);
- else
+ if (!err)
err = gpg_error (GPG_ERR_GENERAL);
goto out;
}
@@ -1101,7 +1189,8 @@ ks_ldap_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec,
if (!err && anykey)
err = dirmngr_status_printf (ctrl, "SOURCE", "%s://%s",
- uri->scheme, uri->host? uri->host:"");
+ use_tls? "ldaps" : "ldap",
+ host? host:"");
}
}
@@ -1123,6 +1212,7 @@ ks_ldap_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec,
}
xfree (basedn);
+ xfree (host);
if (ldap_conn)
ldap_unbind (ldap_conn);
@@ -1157,12 +1247,10 @@ ks_ldap_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern,
}
/* Make sure we are talking to an OpenPGP LDAP server. */
- ldap_err = my_ldap_connect (uri, &ldap_conn, &basedn, &serverinfo);
- if (ldap_err || !basedn)
+ err = my_ldap_connect (uri, &ldap_conn, &basedn, NULL, NULL, &serverinfo);
+ if (err || !basedn)
{
- if (ldap_err)
- err = ldap_err_to_gpg_err (ldap_err);
- else
+ if (!err)
err = GPG_ERR_GENERAL;
goto out;
}
@@ -2050,12 +2138,10 @@ ks_ldap_put (ctrl_t ctrl, parsed_uri_t uri,
return gpg_error (GPG_ERR_NOT_SUPPORTED);
}
- ldap_err = my_ldap_connect (uri, &ldap_conn, &basedn, &serverinfo);
- if (ldap_err || !basedn)
+ err = my_ldap_connect (uri, &ldap_conn, &basedn, NULL, NULL, &serverinfo);
+ if (err || !basedn)
{
- if (ldap_err)
- err = ldap_err_to_gpg_err (ldap_err);
- else
+ if (!err)
err = GPG_ERR_GENERAL;
goto out;
}
diff --git a/dirmngr/ldap.c b/dirmngr/ldap.c
index 96abc89d0..42efcfd49 100644
--- a/dirmngr/ldap.c
+++ b/dirmngr/ldap.c
@@ -560,7 +560,7 @@ start_cert_fetch_ldap (ctrl_t ctrl, cert_fetch_context_t *r_context,
goto leave;
}
base = server->base;
- use_ldaps = server->use_ldaps;
+ use_ldaps = server->ldap_over_tls;
}
else /* Use a default server. */
{
diff --git a/dirmngr/ldapserver.c b/dirmngr/ldapserver.c
index 20a2bb18f..4ef28431c 100644
--- a/dirmngr/ldapserver.c
+++ b/dirmngr/ldapserver.c
@@ -47,18 +47,26 @@ ldapserver_list_free (ldap_server_t servers)
/* Parse a single LDAP server configuration line. Returns the server
- or NULL in case of errors. The configuration line is assumed to be
- colon separated with these fields:
-
- 1. field: Hostname
- 2. field: Portnumber
- 3. field: Username
- 4. field: Password
- 5. field: Base DN
- 6. field: Flags
-
- FILENAME and LINENO are used for diagnostic purposes only.
-*/
+ * or NULL in case of errors. The configuration line is assumed to be
+ * colon separated with these fields:
+ *
+ * 1. field: Hostname
+ * 2. field: Portnumber
+ * 3. field: Username
+ * 4. field: Password
+ * 5. field: Base DN
+ * 6. field: Flags
+ *
+ * Flags are:
+ *
+ * starttls := Use STARTTLS with a default port of 389
+ * ldaptls := Tunnel LDAP trough a TLS tunnel with default port 636
+ * plain := Switch to plain unsecured LDAP.
+ * (The last of these 3 flags is the effective one)
+ * ntds := Use Active Directory authentication
+ *
+ * FILENAME and LINENO are used for diagnostic purposes only.
+ */
ldap_server_t
ldapserver_parse_one (char *line,
const char *filename, unsigned int lineno)
@@ -72,7 +80,13 @@ ldapserver_parse_one (char *line,
int i;
/* Parse the colon separated fields. */
- server = xcalloc (1, sizeof *server);
+ server = xtrycalloc (1, sizeof *server);
+ if (!server)
+ {
+ fail = 1;
+ goto leave;
+ }
+
for (fieldno = 1, p = line; p; p = endp, fieldno++ )
{
endp = strchr (p, ':');
@@ -82,14 +96,9 @@ ldapserver_parse_one (char *line,
switch (fieldno)
{
case 1:
- if (*p)
- server->host = xstrdup (p);
- else
- {
- log_error (_("%s:%u: no hostname given\n"),
- filename, lineno);
- fail = 1;
- }
+ server->host = xtrystrdup (p);
+ if (!server->host)
+ fail = 1;
break;
case 2:
@@ -98,24 +107,36 @@ ldapserver_parse_one (char *line,
break;
case 3:
- if (*p)
- server->user = xstrdup (p);
+ server->user = xtrystrdup (p);
+ if (!server->user)
+ fail = 1;
break;
case 4:
if (*p && !server->user)
{
- log_error (_("%s:%u: password given without user\n"),
- filename, lineno);
+ if (filename)
+ log_error (_("%s:%u: password given without user\n"),
+ filename, lineno);
+ else
+ log_error ("ldap: password given without user ('%s')\n", line);
fail = 1;
}
else if (*p)
- server->pass = xstrdup (p);
+ {
+ server->pass = xtrystrdup (p);
+ if (!server->pass)
+ fail = 1;
+ }
break;
case 5:
if (*p)
- server->base = xstrdup (p);
+ {
+ server->base = xtrystrdup (p);
+ if (!server->base)
+ fail = 1;;
+ }
break;
case 6:
@@ -124,20 +145,45 @@ ldapserver_parse_one (char *line,
flags = strtokenize (p, ",");
if (!flags)
- log_fatal ("strtokenize failed: %s\n",
- gpg_strerror (gpg_error_from_syserror ()));
+ {
+ log_error ("strtokenize failed: %s\n",
+ gpg_strerror (gpg_error_from_syserror ()));
+ fail = 1;
+ break;
+ }
for (i=0; (s = flags[i]); i++)
{
if (!*s)
;
- else if (!ascii_strcasecmp (s, "ldaps"))
- server->use_ldaps = 1;
- else if (!ascii_strcasecmp (s, "ldap"))
- server->use_ldaps = 0;
+ else if (!ascii_strcasecmp (s, "starttls"))
+ {
+ server->starttls = 1;
+ server->ldap_over_tls = 0;
+ }
+ else if (!ascii_strcasecmp (s, "ldaptls"))
+ {
+ server->starttls = 0;
+ server->ldap_over_tls = 1;
+ }
+ else if (!ascii_strcasecmp (s, "plain"))
+ {
+ server->starttls = 0;
+ server->ldap_over_tls = 0;
+ }
+ else if (!ascii_strcasecmp (s, "ntds"))
+ {
+ server->ntds = 1;
+ }
else
- log_info (_("%s:%u: ignoring unknown flag '%s'\n"),
- filename, lineno, s);
+ {
+ if (filename)
+ log_info (_("%s:%u: ignoring unknown flag '%s'\n"),
+ filename, lineno, s);
+ else
+ log_info ("ldap: unknown flag '%s' ignored in (%s)\n",
+ s, line);
+ }
}
xfree (flags);
@@ -150,9 +196,13 @@ ldapserver_parse_one (char *line,
}
}
+ leave:
if (fail)
{
- log_info (_("%s:%u: skipping this line\n"), filename, lineno);
+ if (filename)
+ log_info (_("%s:%u: skipping this line\n"), filename, lineno);
+ else
+ log_info ("ldap: error in server spec ('%s')\n", line);
ldapserver_list_free (server);
server = NULL;
}
diff --git a/dirmngr/ldapserver.h b/dirmngr/ldapserver.h
index 1b20508db..c62f5a939 100644
--- a/dirmngr/ldapserver.h
+++ b/dirmngr/ldapserver.h
@@ -26,18 +26,6 @@
void ldapserver_list_free (ldap_server_t servers);
-/* Parse a single LDAP server configuration line. Returns the server
- or NULL in case of errors. The configuration line is assumed to be
- colon separated with these fields:
-
- 1. field: Hostname
- 2. field: Portnumber
- 3. field: Username
- 4. field: Password
- 5. field: Base DN
-
- FILENAME and LINENO are used for diagnostic purposes only.
-*/
ldap_server_t ldapserver_parse_one (char *line,
const char *filename, unsigned int lineno);
diff --git a/dirmngr/server.c b/dirmngr/server.c
index a35402271..105275845 100644
--- a/dirmngr/server.c
+++ b/dirmngr/server.c
@@ -1143,7 +1143,8 @@ static const char hlp_ldapserver[] =
"LDAPSERVER <data>\n"
"\n"
"Add a new LDAP server to the list of configured LDAP servers.\n"
- "DATA is in the same format as expected in the configure file.";
+ "DATA is in the same format as expected in the configure file.\n"
+ "An optional prefix \"ldap:\" is allowed.";
static gpg_error_t
cmd_ldapserver (assuan_context_t ctx, char *line)
{
@@ -1157,7 +1158,11 @@ cmd_ldapserver (assuan_context_t ctx, char *line)
if (*line == '\0')
return leave_cmd (ctx, PARM_ERROR (_("ldapserver missing")));
- server = ldapserver_parse_one (line, "", 0);
+ /* Skip an "ldap:" prefix unless it is a valid ldap url. */
+ if (!strncmp (line, "ldap:", 5) && !(line[5] == '/' && line[6] == '/'))
+ line += 5;
+
+ server = ldapserver_parse_one (line, NULL, 0);
if (! server)
return leave_cmd (ctx, gpg_error (GPG_ERR_INV_ARG));
@@ -2065,6 +2070,7 @@ make_keyserver_item (const char *uri, uri_item_t *r_item)
{
gpg_error_t err;
uri_item_t item;
+ const char *s;
*r_item = NULL;
@@ -2108,8 +2114,43 @@ make_keyserver_item (const char *uri, uri_item_t *r_item)
strcpy (item->uri, uri);
#if USE_LDAP
- if (ldap_uri_p (item->uri))
- err = ldap_parse_uri (&item->parsed_uri, uri);
+ if (!strncmp (uri, "ldap:", 5) && !(uri[5] == '/' && uri[6] == '/'))
+ {
+ char *tmpstr;
+ /* Special ldap scheme given. This differs from a valid ldap
+ * scheme in that no double slash follows.. Use http_parse_uri
+ * to put it as opaque value into parsed_uri. */
+ tmpstr = strconcat ("opaque:", uri+5, NULL);
+ if (!tmpstr)
+ err = gpg_error_from_syserror ();
+ else
+ {
+ log_debug ("tmpstr='%s'\n", tmpstr);
+ err = http_parse_uri (&item->parsed_uri, tmpstr, 0);
+ xfree (tmpstr);
+ }
+ }
+ else if ((s=strchr (uri, ':')) && !(s[1] == '/' && s[2] == '/'))
+ {
+ char *tmpstr;
+ /* No valid scheme given. Use http_parse_uri to put the string
+ * as opaque value into parsed_uri. */
+ tmpstr = strconcat ("opaque:", uri, NULL);
+ if (!tmpstr)
+ err = gpg_error_from_syserror ();
+ else
+ {
+ log_debug ("tmpstr2='%s'\n", tmpstr);
+ err = http_parse_uri (&item->parsed_uri, tmpstr, 0);
+ xfree (tmpstr);
+ }
+ }
+ else if (ldap_uri_p (uri))
+ {
+ /* Fixme: We should get rid of that parser and replace it with
+ * our generic (http) URI parser. */
+ err = ldap_parse_uri (&item->parsed_uri, uri);
+ }
else
#endif
{