gpgsm: Allow sepcification of ldaps servers.

* sm/gpgsm.h (struct keyserver_spec): Add field use_ldaps.
* sm/gpgsm.c (parse_keyserver_line): Parse flags.
* sm/call-dirmngr.c (prepare_dirmngr): Send ldaps flag to the dirmngr.

* dirmngr/dirmngr.h (struct ldap_server_s): Add field use_ldaps.
* dirmngr/ldapserver.c (ldapserver_parse_one): Parse flags.
* dirmngr/ldap.c (start_cert_fetch_ldap): Call wrapper with --tls.

* dirmngr/dirmngr_ldap.c: New option --tls.
(fetch_ldap): Make use of that option.
--

There was no way to specify an LDAPS server in
dirmngr_ldapserver.socnf or with gpgsm's --keyserver option.  This
patch fixes this.  Eventually we should allow to replace host and port
by a partial URI in the same way ldap_initialize does it.  For backward
compatibility we do not yet do that.

Although the dirmngr code accepts an URL (eg. taken from a
certificate), I can't see how the scheme was ever used.  Thus the
patch also detects an ldaps scheme and uses this.  That part has not
been tested, though.

Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
Werner Koch 2019-11-09 11:29:59 +01:00
parent 2b9d399cf0
commit 6e1c99bc39
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
9 changed files with 145 additions and 17 deletions

View File

@ -50,6 +50,7 @@ struct ldap_server_s
char *user;
char *pass;
char *base;
unsigned int use_ldaps:1;
};
typedef struct ldap_server_s *ldap_server_t;

View File

@ -123,6 +123,7 @@ enum
oDN,
oFilter,
oAttr,
oTls,
oOnlySearchTimeout,
oLogWithPID
@ -138,6 +139,7 @@ static ARGPARSE_OPTS opts[] = {
" a record oriented format")},
{ oProxy, "proxy", 2,
N_("|NAME|ignore host part and connect through NAME")},
{ oTls, "tls", 0, N_("force a TLS connection")},
{ oHost, "host", 2, N_("|NAME|connect to host NAME")},
{ oPort, "port", 1, N_("|N|connect to port N")},
{ oUser, "user", 2, N_("|NAME|use user NAME for authentication")},
@ -163,6 +165,7 @@ struct my_opt_s
my_ldap_timeval_t timeout;/* Timeout for the LDAP search functions. */
unsigned int alarm_timeout; /* And for the alarm based timeout. */
int multi;
int force_tls;
estream_t outstream; /* Send output to this stream. */
@ -287,6 +290,7 @@ ldap_wrapper_main (char **argv, estream_t outstream)
myopt->pass = getenv ("DIRMNGR_LDAP_PASS");
break;
case oProxy: myopt->proxy = pargs.r.ret_str; break;
case oTls: myopt->force_tls = 1; break;
case oHost: myopt->host = pargs.r.ret_str; break;
case oPort: myopt->port = pargs.r.ret_int; break;
case oDN: myopt->dn = pargs.r.ret_str; break;
@ -622,12 +626,19 @@ fetch_ldap (my_opt_t myopt, const char *url, const LDAPURLDesc *ludp)
attrs[1] = NULL;
attr = attrs[0];
if (!port)
if (!port && myopt->force_tls)
port = 636;
else if (!port)
port = (ludp->lud_scheme && !strcmp (ludp->lud_scheme, "ldaps"))? 636:389;
if (myopt->verbose)
{
log_info (_("processing url '%s'\n"), url);
if (myopt->force_tls)
log_info ("forcing tls\n");
else
log_info ("not forcing tls\n");
if (myopt->user)
log_info (_(" user '%s'\n"), myopt->user);
if (myopt->pass)
@ -665,17 +676,48 @@ fetch_ldap (my_opt_t myopt, const char *url, const LDAPURLDesc *ludp)
&& ludp->lud_attrs && ludp->lud_attrs[0] && ludp->lud_attrs[1])
log_info (_("WARNING: using first attribute only\n"));
set_timeout (myopt);
npth_unprotect ();
ld = my_ldap_init (host, port);
npth_protect ();
if (!ld)
if (myopt->force_tls
|| (ludp->lud_scheme && !strcmp (ludp->lud_scheme, "ldaps")))
{
log_error (_("LDAP init to '%s:%d' failed: %s\n"),
host, port, strerror (errno));
return -1;
char *uri;
uri = xtryasprintf ("ldaps://%s:%d", host, port);
if (!uri)
{
log_error (_("error allocating memory: %s\n"),
gpg_strerror (gpg_error_from_syserror ()));
return -1;
}
ret = ldap_initialize (&ld, uri);
if (ret)
{
log_error (_("LDAP init to '%s' failed: %s\n"),
uri, ldap_err2string (ret));
xfree (uri);
return -1;
}
else if (myopt->verbose)
log_info (_("LDAP init to '%s' done\n"), uri);
xfree (uri);
}
else
{
/* Keep the old way so to avoid regressions. Eventually we
* should really consider the supplied scheme and use only
* ldap_initialize. */
npth_unprotect ();
ld = my_ldap_init (host, port);
npth_protect ();
if (!ld)
{
log_error (_("LDAP init to '%s:%d' failed: %s\n"),
host, port, strerror (errno));
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);

View File

@ -525,7 +525,7 @@ start_cert_fetch_ldap (ctrl_t ctrl, cert_fetch_context_t *context,
int argc = 0;
int argc_malloced = 0;
char portbuf[30], timeoutbuf[30];
int use_ldaps = 0;
*context = NULL;
@ -554,7 +554,7 @@ start_cert_fetch_ldap (ctrl_t ctrl, cert_fetch_context_t *context,
goto leave;
}
base = server->base;
use_ldaps = server->use_ldaps;
}
else /* Use a default server. */
return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
@ -587,6 +587,8 @@ start_cert_fetch_ldap (ctrl_t ctrl, cert_fetch_context_t *context,
argv[argc++] = "--proxy";
argv[argc++] = proxy;
}
if (use_ldaps)
argv[argc++] = "--tls";
if (host)
{
argv[argc++] = "--host";

View File

@ -55,6 +55,7 @@ ldapserver_list_free (ldap_server_t servers)
3. field: Username
4. field: Password
5. field: Base DN
6. field: Flags
FILENAME and LINENO are used for diagnostic purposes only.
*/
@ -64,9 +65,11 @@ ldapserver_parse_one (char *line,
{
char *p;
char *endp;
const char *s;
ldap_server_t server;
int fieldno;
int fail = 0;
int i;
/* Parse the colon separated fields. */
server = xcalloc (1, sizeof *server);
@ -115,6 +118,32 @@ ldapserver_parse_one (char *line,
server->base = xstrdup (p);
break;
case 6:
{
char **flags = NULL;
flags = strtokenize (p, ",");
if (!flags)
log_fatal ("strtokenize failed: %s\n",
gpg_strerror (gpg_error_from_syserror ()));
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
log_info (_("%s:%u: ignoring unknown flag '%s'\n"),
filename, lineno, s);
}
xfree (flags);
}
break;
default:
/* (We silently ignore extra fields.) */
break;

View File

@ -406,10 +406,14 @@ client for its session. The default value for @var{file} is
This server list file contains one LDAP server per line in the format
@sc{hostname:port:username:password:base_dn}
@sc{hostname:port:username:password:base_dn:flags}
Lines starting with a @samp{#} are comments.
The only defined flag is @code{ldaps} to specify that a TLS
connections shall be used. Flags are comma delimited; unknown flags
are ignored.
Note that as usual all strings entered are expected to be UTF-8 encoded.
Obviously this will lead to problems if the password has originally been
encoded as Latin-1. There is no other solution here than to put such a

View File

@ -356,13 +356,27 @@ Note that the @command{dirmngr} can in addition be configured with a
default list of LDAP servers to be used after those configured with
this option. The syntax of @var{string} is:
@sc{hostname:port:username:password:base_dn}
@sc{hostname:port:username:password:base_dn:flags}
The only defined flag is @code{ldaps} to specify that a TLS
connections shall be used. Flags are comma delimited; unknown flags
are ignored.
Note that all parts of that string are expected to be UTF-8 encoded.
This may lead to problems if the @sc{password} has originally been
encoded as Latin-1; in such a case better configure this LDAP server
encoded as Latin-1; in such a case better configure tsuch an LDAP server
using the global configuration of @command{dirmngr}.
Here is an example which uses the default port, no username, no
password, and requests a TLS connection:
@c man:.RS
@example
--keyserver ldap.pca.dfn.de::::o=DFN-Verein,c=DE:ldaps
@end example
@c man:.RE
@item --policy-file @var{filename}
@opindex policy-file
Change the default name of the policy file to @var{filename}. The

View File

@ -223,8 +223,9 @@ prepare_dirmngr (ctrl_t ctrl, assuan_context_t ctx, gpg_error_t err)
char *pass = server->pass ? server->pass : "";
char *base = server->base ? server->base : "";
snprintf (line, DIM (line), "LDAPSERVER %s:%i:%s:%s:%s",
server->host, server->port, user, pass, base);
snprintf (line, DIM (line), "LDAPSERVER %s:%i:%s:%s:%s:%s",
server->host, server->port, user, pass, base,
server->use_ldaps? "ldaps":"");
assuan_transact (ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
/* The code below is not required because we don't return an error. */

View File

@ -817,9 +817,17 @@ parse_keyserver_line (char *line,
{
char *p;
char *endp;
const char *s;
struct keyserver_spec *server;
int fieldno;
int fail = 0;
int i;
if (!filename)
{
filename = "[cmd]";
lineno = 0;
}
/* Parse the colon separated fields. */
server = xcalloc (1, sizeof *server);
@ -833,7 +841,7 @@ parse_keyserver_line (char *line,
{
case 1:
if (*p)
server->host = xstrdup (p);
server->host = xstrdup (p);
else
{
log_error (_("%s:%u: no hostname given\n"),
@ -868,6 +876,32 @@ parse_keyserver_line (char *line,
server->base = xstrdup (p);
break;
case 6:
{
char **flags = NULL;
flags = strtokenize (p, ",");
if (!flags)
log_fatal ("strtokenize failed: %s\n",
gpg_strerror (gpg_error_from_syserror ()));
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
log_info (_("%s:%u: ignoring unknown flag '%s'\n"),
filename, lineno, s);
}
xfree (flags);
}
break;
default:
/* (We silently ignore extra fields.) */
break;

View File

@ -48,6 +48,7 @@ struct keyserver_spec
char *user;
char *pass;
char *base;
unsigned int use_ldaps:1;
};