dirmngr: Allow for non-URL specified ldap keyservers.

* dirmngr/server.c (cmd_ldapserver): Strip an optional prefix.
(make_keyserver_item): Handle non-URL ldap specs.
* dirmngr/dirmngr.h (struct ldap_server_s): Add fields starttls,
ldap_over_tls, and ntds.

* dirmngr/ldapserver.c (ldapserver_parse_one): Add for an empty host
string.  Improve error messages for the non-file case.  Support flags.
* dirmngr/ks-action.c (ks_action_help): Handle non-URL ldap specs.
(ks_action_search, ks_action_get, ks_action_put): Ditto.
* dirmngr/ks-engine-ldap.c: Include ldapserver.h.
(ks_ldap_help): Handle non-URL ldap specs.
(my_ldap_connect): Add args r_host and r_use_tls.  Rewrite to support
URLs and non-URL specified keyservers.
(ks_ldap_get): Adjust for changes in my_ldap_connect.
(ks_ldap_search): Ditto.
(ks_ldap_put): Ditto.
--

The idea here is to unify our use of URLS or colon delimited ldap
keyserver specification.  The requirement for percent escaping, for
example the bindname in an URLs, is cumbersome and prone to errors.
This we allow our classic colon delimited format as an alternative.
That format makes it also easy to specify flags to tell dirmngr
whether to use starttls or ldap-over-tls.  The code is nearly 100%
compatible to existing specification.  There is one ambiguity if the
hostname for CRL/X509 searches is just "ldap"; this can be solved by
prefixing it with "ldap:" (already implemented in gpgsm).

GnuPG-bug-id: 5405, 5452
Ported-from: 2b4cddf908
This commit is contained in:
Werner Koch 2021-05-26 14:48:27 +02:00
parent bebc71d229
commit eb3a629154
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
7 changed files with 366 additions and 167 deletions

View File

@ -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;

View File

@ -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)

View File

@ -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;
}

View File

@ -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. */
{

View File

@ -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;
}

View File

@ -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);

View File

@ -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
{