2010-06-09 16:53:51 +00:00
|
|
|
|
/* ldap.c - LDAP access
|
|
|
|
|
* Copyright (C) 2002 Klarälvdalens Datakonsult AB
|
2021-06-08 08:46:59 +02:00
|
|
|
|
* Copyright (C) 2003, 2004, 2005, 2007, 2008, 2010, 2021 g10 Code GmbH
|
2010-06-09 16:53:51 +00:00
|
|
|
|
*
|
2021-06-08 08:46:59 +02:00
|
|
|
|
* This file is part of GnuPG.
|
2010-06-09 16:53:51 +00:00
|
|
|
|
*
|
2021-06-08 08:46:59 +02:00
|
|
|
|
* GnuPG is free software; you can redistribute it and/or modify
|
2010-06-09 16:53:51 +00:00
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
2021-06-08 08:46:59 +02:00
|
|
|
|
* the Free Software Foundation; either version 3 of the License, or
|
2010-06-09 16:53:51 +00:00
|
|
|
|
* (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* DirMngr is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
2021-06-08 08:46:59 +02:00
|
|
|
|
* along with this program; if not, see <https://www.gnu.org/licenses/>.
|
|
|
|
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
2010-06-09 16:53:51 +00:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
#include <time.h>
|
Port to npth.
* configure.ac: Don't check for PTH but for NPTH.
(AH_BOTTOM): Remove PTH_SYSCALL_SOFT.
(have_pth): Rename to ...
(have_npth): ... this.
(USE_GNU_NPTH): Rename to ...
(USE_GNU_PTH): ... this.
* m4/npth.m4: New file.
* agent/Makefile.am, agent/cache.c, agent/call-pinentry.c,
agent/call-scd.c, agent/findkey.c, agent/gpg-agent.c,
agent/trustlist.c, common/Makefile.am, common/estream.c,
common/exechelp-posix.c, common/exechelp-w32.c,
common/exechelp-w32ce.c, common/http.c, common/init.c,
common/sysutils.c, dirmngr/Makefile.am, dirmngr/crlfetch.c,
dirmngr/dirmngr.c, dirmngr/dirmngr_ldap.c, dirmngr/ldap-wrapper-ce.c,
dirmngr/ldap-wrapper.c, dirmngr/ldap.c, g13/Makefile.am,
g13/call-gpg.c, g13/g13.c, g13/runner.c, scd/Makefile.am,
scd/apdu.c, scd/app.c, scd/ccid-driver.c, scd/command.c,
scd/scdaemon.c, tools/Makefile.am: Port to npth.
2012-01-03 22:12:37 +01:00
|
|
|
|
#include <npth.h>
|
2010-06-09 16:53:51 +00:00
|
|
|
|
|
|
|
|
|
#include "dirmngr.h"
|
2017-03-07 20:21:23 +09:00
|
|
|
|
#include "../common/exechelp.h"
|
2010-06-09 16:53:51 +00:00
|
|
|
|
#include "crlfetch.h"
|
|
|
|
|
#include "ldapserver.h"
|
|
|
|
|
#include "misc.h"
|
2010-07-23 16:16:14 +00:00
|
|
|
|
#include "ldap-wrapper.h"
|
2021-06-08 08:46:59 +02:00
|
|
|
|
#include "ldap-url.h"
|
2017-03-07 20:21:23 +09:00
|
|
|
|
#include "../common/host2net.h"
|
2010-06-09 16:53:51 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define UNENCODED_URL_CHARS "abcdefghijklmnopqrstuvwxyz" \
|
|
|
|
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
|
|
|
|
|
"01234567890" \
|
|
|
|
|
"$-_.+!*'(),"
|
|
|
|
|
#define USERCERTIFICATE "userCertificate"
|
|
|
|
|
#define CACERTIFICATE "caCertificate"
|
|
|
|
|
#define X509CACERT "x509caCert"
|
|
|
|
|
#define USERSMIMECERTIFICATE "userSMIMECertificate"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Definition for the context of the cert fetch functions. */
|
|
|
|
|
struct cert_fetch_context_s
|
|
|
|
|
{
|
|
|
|
|
ksba_reader_t reader; /* The reader used (shallow copy). */
|
|
|
|
|
unsigned char *tmpbuf; /* Helper buffer. */
|
|
|
|
|
size_t tmpbufsize; /* Allocated size of tmpbuf. */
|
|
|
|
|
int truncated; /* Flag to indicate a truncated output. */
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Add HOST and PORT to our list of LDAP servers. Fixme: We should
|
|
|
|
|
better use an extra list of servers. */
|
|
|
|
|
static void
|
|
|
|
|
add_server_to_servers (const char *host, int port)
|
|
|
|
|
{
|
|
|
|
|
ldap_server_t server;
|
|
|
|
|
ldap_server_t last = NULL;
|
|
|
|
|
const char *s;
|
|
|
|
|
|
|
|
|
|
if (!port)
|
|
|
|
|
port = 389;
|
|
|
|
|
|
|
|
|
|
for (server=opt.ldapservers; server; server = server->next)
|
|
|
|
|
{
|
|
|
|
|
if (!strcmp (server->host, host) && server->port == port)
|
|
|
|
|
return; /* already in list... */
|
|
|
|
|
last = server;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* We assume that the host names are all supplied by our
|
|
|
|
|
configuration files and thus are sane. To keep this assumption
|
|
|
|
|
we must reject all invalid host names. */
|
|
|
|
|
for (s=host; *s; s++)
|
|
|
|
|
if (!strchr ("abcdefghijklmnopqrstuvwxyz"
|
|
|
|
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
|
|
|
"01234567890.-", *s))
|
|
|
|
|
{
|
|
|
|
|
log_error (_("invalid char 0x%02x in host name - not added\n"), *s);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2012-06-05 19:29:22 +02:00
|
|
|
|
log_info (_("adding '%s:%d' to the ldap server list\n"), host, port);
|
2010-06-09 16:53:51 +00:00
|
|
|
|
server = xtrycalloc (1, sizeof *s);
|
|
|
|
|
if (!server)
|
|
|
|
|
log_error (_("malloc failed: %s\n"), strerror (errno));
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
server->host = xstrdup (host);
|
|
|
|
|
server->port = port;
|
|
|
|
|
if (last)
|
|
|
|
|
last->next = server;
|
|
|
|
|
else
|
|
|
|
|
opt.ldapservers = server;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Perform an LDAP query. Returns an gpg error code or 0 on success.
|
|
|
|
|
The function returns a new reader object at READER. */
|
|
|
|
|
static gpg_error_t
|
2011-02-04 12:57:53 +01:00
|
|
|
|
run_ldap_wrapper (ctrl_t ctrl,
|
2010-06-09 16:53:51 +00:00
|
|
|
|
int ignore_timeout,
|
|
|
|
|
int multi_mode,
|
2021-06-08 08:46:59 +02:00
|
|
|
|
int tls_mode,
|
|
|
|
|
int ntds,
|
2010-06-09 16:53:51 +00:00
|
|
|
|
const char *proxy,
|
2011-02-04 12:57:53 +01:00
|
|
|
|
const char *host, int port,
|
2010-06-09 16:53:51 +00:00
|
|
|
|
const char *user, const char *pass,
|
2021-06-08 08:46:59 +02:00
|
|
|
|
const char *base, const char *filter, const char *attr,
|
2010-06-09 16:53:51 +00:00
|
|
|
|
ksba_reader_t *reader)
|
|
|
|
|
{
|
2021-06-08 08:46:59 +02:00
|
|
|
|
const char *argv[50];
|
2010-06-09 16:53:51 +00:00
|
|
|
|
int argc;
|
|
|
|
|
char portbuf[30], timeoutbuf[30];
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2010-06-09 16:53:51 +00:00
|
|
|
|
|
|
|
|
|
*reader = NULL;
|
|
|
|
|
|
|
|
|
|
argc = 0;
|
2021-06-08 08:46:59 +02:00
|
|
|
|
if (pass && *pass) /* Note, that the password must be the first item. */
|
2010-06-09 16:53:51 +00:00
|
|
|
|
{
|
|
|
|
|
argv[argc++] = "--pass";
|
|
|
|
|
argv[argc++] = pass;
|
|
|
|
|
}
|
2018-04-27 11:57:08 +02:00
|
|
|
|
|
|
|
|
|
if (DBG_LOOKUP)
|
2010-06-09 16:53:51 +00:00
|
|
|
|
argv[argc++] = "-vv";
|
2018-04-27 11:57:08 +02:00
|
|
|
|
else if (DBG_EXTPROG)
|
|
|
|
|
argv[argc++] = "-v";
|
|
|
|
|
|
2010-06-09 16:53:51 +00:00
|
|
|
|
argv[argc++] = "--log-with-pid";
|
|
|
|
|
if (multi_mode)
|
|
|
|
|
argv[argc++] = "--multi";
|
2021-06-08 08:46:59 +02:00
|
|
|
|
|
|
|
|
|
if (tls_mode == 1)
|
|
|
|
|
argv[argc++] = "--starttls";
|
|
|
|
|
else if (tls_mode)
|
|
|
|
|
argv[argc++] = "--ldaptls";
|
|
|
|
|
|
|
|
|
|
if (ntds)
|
|
|
|
|
argv[argc++] = "--ntds";
|
|
|
|
|
|
2010-06-09 16:53:51 +00:00
|
|
|
|
if (opt.ldaptimeout)
|
|
|
|
|
{
|
2021-06-08 08:46:59 +02:00
|
|
|
|
snprintf (timeoutbuf, sizeof timeoutbuf, "%u", opt.ldaptimeout);
|
2010-06-09 16:53:51 +00:00
|
|
|
|
argv[argc++] = "--timeout";
|
|
|
|
|
argv[argc++] = timeoutbuf;
|
|
|
|
|
if (ignore_timeout)
|
|
|
|
|
argv[argc++] = "--only-search-timeout";
|
|
|
|
|
}
|
|
|
|
|
if (proxy)
|
|
|
|
|
{
|
|
|
|
|
argv[argc++] = "--proxy";
|
|
|
|
|
argv[argc++] = proxy;
|
|
|
|
|
}
|
2021-06-08 08:46:59 +02:00
|
|
|
|
if (host && *host)
|
2010-06-09 16:53:51 +00:00
|
|
|
|
{
|
|
|
|
|
argv[argc++] = "--host";
|
|
|
|
|
argv[argc++] = host;
|
|
|
|
|
}
|
|
|
|
|
if (port)
|
|
|
|
|
{
|
|
|
|
|
sprintf (portbuf, "%d", port);
|
|
|
|
|
argv[argc++] = "--port";
|
|
|
|
|
argv[argc++] = portbuf;
|
|
|
|
|
}
|
2021-06-08 08:46:59 +02:00
|
|
|
|
if (user && *user)
|
2010-06-09 16:53:51 +00:00
|
|
|
|
{
|
|
|
|
|
argv[argc++] = "--user";
|
|
|
|
|
argv[argc++] = user;
|
|
|
|
|
}
|
2021-06-08 08:46:59 +02:00
|
|
|
|
if (base && *base)
|
2010-06-09 16:53:51 +00:00
|
|
|
|
{
|
2021-06-08 08:46:59 +02:00
|
|
|
|
argv[argc++] = "--base";
|
|
|
|
|
argv[argc++] = base;
|
2010-06-09 16:53:51 +00:00
|
|
|
|
}
|
|
|
|
|
if (attr)
|
|
|
|
|
{
|
|
|
|
|
argv[argc++] = "--attr";
|
|
|
|
|
argv[argc++] = attr;
|
|
|
|
|
}
|
2021-06-08 08:46:59 +02:00
|
|
|
|
|
|
|
|
|
if (filter)
|
|
|
|
|
argv[argc++] = filter;
|
2010-06-09 16:53:51 +00:00
|
|
|
|
argv[argc] = NULL;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2010-06-09 16:53:51 +00:00
|
|
|
|
return ldap_wrapper (ctrl, reader, argv);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Perform a LDAP query using a given URL. On success a new ksba
|
|
|
|
|
reader is returned. If HOST or PORT are not 0, they are used to
|
|
|
|
|
override the values from the URL. */
|
|
|
|
|
gpg_error_t
|
2021-06-08 08:46:59 +02:00
|
|
|
|
url_fetch_ldap (ctrl_t ctrl, const char *url, ksba_reader_t *reader)
|
2010-06-09 16:53:51 +00:00
|
|
|
|
{
|
|
|
|
|
gpg_error_t err;
|
2021-06-08 08:46:59 +02:00
|
|
|
|
LDAPURLDesc *ludp = NULL;
|
|
|
|
|
int tls_mode;
|
|
|
|
|
|
|
|
|
|
if (!ldap_is_ldap_url (url))
|
|
|
|
|
{
|
|
|
|
|
log_error (_("'%s' is not an LDAP URL\n"), url);
|
|
|
|
|
return gpg_error (GPG_ERR_INV_URI);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ldap_url_parse (url, &ludp))
|
|
|
|
|
{
|
|
|
|
|
log_error (_("'%s' is an invalid LDAP URL\n"), url);
|
|
|
|
|
return gpg_error (GPG_ERR_INV_URI);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ludp->lud_filter && ludp->lud_filter[0] != '(')
|
|
|
|
|
{
|
|
|
|
|
log_error (_("'%s' is an invalid LDAP URL\n"), url);
|
|
|
|
|
err = gpg_error (GPG_ERR_BAD_URI);
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ludp->lud_scheme && !strcmp (ludp->lud_scheme, "ldaps"))
|
|
|
|
|
tls_mode = 2; /* LDAP-over-TLS here becuase we get it from certs. */
|
|
|
|
|
else
|
|
|
|
|
tls_mode = 0;
|
2010-06-09 16:53:51 +00:00
|
|
|
|
|
|
|
|
|
err = run_ldap_wrapper (ctrl,
|
|
|
|
|
1, /* Ignore explicit timeout because CRLs
|
|
|
|
|
might be very large. */
|
2021-06-08 08:46:59 +02:00
|
|
|
|
0, /* No Multi-mode. */
|
|
|
|
|
tls_mode,
|
|
|
|
|
0, /* No AD authentication. */
|
2010-06-09 16:53:51 +00:00
|
|
|
|
opt.ldap_proxy,
|
2021-06-08 08:46:59 +02:00
|
|
|
|
ludp->lud_host, ludp->lud_port,
|
|
|
|
|
NULL, NULL, /* user, password */
|
|
|
|
|
ludp->lud_dn, /* Base DN */
|
|
|
|
|
ludp->lud_filter,
|
|
|
|
|
ludp->lud_attrs? ludp->lud_attrs[0] : NULL,
|
2010-06-09 16:53:51 +00:00
|
|
|
|
reader);
|
|
|
|
|
|
|
|
|
|
/* FIXME: This option might be used for DoS attacks. Because it
|
|
|
|
|
will enlarge the list of servers to consult without a limit and
|
|
|
|
|
all LDAP queries w/o a host are will then try each host in
|
|
|
|
|
turn. */
|
2011-02-04 12:57:53 +01:00
|
|
|
|
if (!err && opt.add_new_ldapservers && !opt.ldap_proxy)
|
2010-06-09 16:53:51 +00:00
|
|
|
|
{
|
2021-06-08 08:46:59 +02:00
|
|
|
|
if (ludp->lud_host)
|
|
|
|
|
add_server_to_servers (ludp->lud_host, ludp->lud_port);
|
2010-06-09 16:53:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If the lookup failed and we are not only using the proxy, we try
|
|
|
|
|
again using our default list of servers. */
|
|
|
|
|
if (err && !(opt.ldap_proxy && opt.only_ldap_proxy))
|
|
|
|
|
{
|
|
|
|
|
struct ldapserver_iter iter;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2010-06-09 16:53:51 +00:00
|
|
|
|
if (DBG_LOOKUP)
|
|
|
|
|
log_debug ("no hostname in URL or query failed; "
|
|
|
|
|
"trying all default hostnames\n");
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2010-06-09 16:53:51 +00:00
|
|
|
|
for (ldapserver_iter_begin (&iter, ctrl);
|
|
|
|
|
err && ! ldapserver_iter_end_p (&iter);
|
|
|
|
|
ldapserver_iter_next (&iter))
|
|
|
|
|
{
|
|
|
|
|
ldap_server_t server = iter.server;
|
|
|
|
|
|
2021-06-08 08:46:59 +02:00
|
|
|
|
if (server->starttls)
|
|
|
|
|
tls_mode = 1;
|
|
|
|
|
else if (server->ldap_over_tls)
|
|
|
|
|
tls_mode = 2;
|
|
|
|
|
else
|
|
|
|
|
tls_mode = 0;
|
|
|
|
|
|
2010-06-09 16:53:51 +00:00
|
|
|
|
err = run_ldap_wrapper (ctrl,
|
|
|
|
|
0,
|
2021-06-08 08:46:59 +02:00
|
|
|
|
0, /* No Multi-mode */
|
|
|
|
|
tls_mode,
|
|
|
|
|
server->ntds,
|
2010-06-09 16:53:51 +00:00
|
|
|
|
NULL,
|
|
|
|
|
server->host, server->port,
|
2021-06-08 08:46:59 +02:00
|
|
|
|
server->user, server->pass,
|
|
|
|
|
server->base,
|
|
|
|
|
ludp->lud_filter,
|
|
|
|
|
ludp->lud_attrs? ludp->lud_attrs[0] : NULL,
|
2010-06-09 16:53:51 +00:00
|
|
|
|
reader);
|
|
|
|
|
if (!err)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-08 08:46:59 +02:00
|
|
|
|
leave:
|
|
|
|
|
ldap_free_urldesc (ludp);
|
2010-06-09 16:53:51 +00:00
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Perform an LDAP query on all configured servers. On error the
|
|
|
|
|
error code of the last try is returned. */
|
|
|
|
|
gpg_error_t
|
|
|
|
|
attr_fetch_ldap (ctrl_t ctrl,
|
|
|
|
|
const char *dn, const char *attr, ksba_reader_t *reader)
|
|
|
|
|
{
|
|
|
|
|
gpg_error_t err = gpg_error (GPG_ERR_CONFIGURATION);
|
|
|
|
|
struct ldapserver_iter iter;
|
|
|
|
|
|
|
|
|
|
*reader = NULL;
|
|
|
|
|
|
2021-06-08 08:46:59 +02:00
|
|
|
|
/* FIXME; we might want to look at the Base DN to try matching
|
2010-06-09 16:53:51 +00:00
|
|
|
|
servers first. */
|
|
|
|
|
for (ldapserver_iter_begin (&iter, ctrl); ! ldapserver_iter_end_p (&iter);
|
|
|
|
|
ldapserver_iter_next (&iter))
|
|
|
|
|
{
|
|
|
|
|
ldap_server_t server = iter.server;
|
2021-06-08 08:46:59 +02:00
|
|
|
|
int tls_mode;
|
|
|
|
|
|
|
|
|
|
if (server->starttls)
|
|
|
|
|
tls_mode = 1;
|
|
|
|
|
else if (server->ldap_over_tls)
|
|
|
|
|
tls_mode = 2;
|
|
|
|
|
else
|
|
|
|
|
tls_mode = 0;
|
2010-06-09 16:53:51 +00:00
|
|
|
|
|
|
|
|
|
err = run_ldap_wrapper (ctrl,
|
|
|
|
|
0,
|
|
|
|
|
0,
|
2021-06-08 08:46:59 +02:00
|
|
|
|
tls_mode,
|
|
|
|
|
server->ntds,
|
2010-06-09 16:53:51 +00:00
|
|
|
|
opt.ldap_proxy,
|
|
|
|
|
server->host, server->port,
|
|
|
|
|
server->user, server->pass,
|
2021-06-08 08:46:59 +02:00
|
|
|
|
dn,
|
|
|
|
|
"(objectClass=*)",
|
|
|
|
|
attr,
|
2010-06-09 16:53:51 +00:00
|
|
|
|
reader);
|
|
|
|
|
if (!err)
|
|
|
|
|
break; /* Probably found a result. Ready. */
|
|
|
|
|
}
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-08 08:46:59 +02:00
|
|
|
|
|
2010-06-09 16:53:51 +00:00
|
|
|
|
|
2021-06-08 08:46:59 +02:00
|
|
|
|
/* Return true if VALUE needs escaping. */
|
|
|
|
|
static int
|
|
|
|
|
rfc2254_need_escape (const char *value)
|
|
|
|
|
{
|
|
|
|
|
/* NUL needs to be escaped as well but we can represent that in
|
|
|
|
|
* VALUE, so no need for it. */
|
|
|
|
|
return !!strpbrk (value, "*()\\");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Escape VALUE using RFC-2254 rules. Returns NULL on error. */
|
|
|
|
|
static char *
|
|
|
|
|
rfc2254_escape (const char *value)
|
|
|
|
|
{
|
|
|
|
|
const char *s;
|
|
|
|
|
char *buffer, *p;
|
|
|
|
|
size_t length = 0;
|
|
|
|
|
|
|
|
|
|
for (s=value; *s; s++)
|
|
|
|
|
switch (*s)
|
|
|
|
|
{
|
|
|
|
|
case '*':
|
|
|
|
|
case '(':
|
|
|
|
|
case ')':
|
|
|
|
|
case '\\': length += 3; break;
|
|
|
|
|
default: length++; break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
buffer = xtrymalloc (length+1);
|
|
|
|
|
if (!buffer)
|
|
|
|
|
return NULL;
|
|
|
|
|
p = buffer;
|
|
|
|
|
for (s=value; *s; s++)
|
|
|
|
|
switch (*s)
|
|
|
|
|
{
|
|
|
|
|
case '*': p = stpcpy (p, "\\2a"); break;
|
|
|
|
|
case '(': p = stpcpy (p, "\\28"); break;
|
|
|
|
|
case ')': p = stpcpy (p, "\\29"); break;
|
|
|
|
|
case '\\': p = stpcpy (p, "\\5c"); break;
|
|
|
|
|
default: *p++ = *s; break;
|
|
|
|
|
}
|
|
|
|
|
*p = 0;
|
|
|
|
|
return buffer;
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-09 16:53:51 +00:00
|
|
|
|
|
2021-06-08 08:46:59 +02:00
|
|
|
|
/* Return true if VALUE needs escaping. */
|
|
|
|
|
static int
|
|
|
|
|
extfilt_need_escape (const char *value)
|
|
|
|
|
{
|
|
|
|
|
/* NUL needs to be escaped as well but we can represent that in
|
|
|
|
|
* VALUE, so no need for it. */
|
|
|
|
|
return !!strchr (value, '&');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Escape VALUE using our extended filter rules from dirmngr_ldap.c.
|
|
|
|
|
* Returns NULL on error. */
|
|
|
|
|
static char *
|
|
|
|
|
extfilt_escape (const char *value)
|
|
|
|
|
{
|
|
|
|
|
const char *s;
|
|
|
|
|
char *buffer, *p;
|
|
|
|
|
size_t length = 0;
|
|
|
|
|
|
|
|
|
|
for (s=value; *s; s++)
|
|
|
|
|
{
|
|
|
|
|
length++;
|
|
|
|
|
if (*s == '&')
|
|
|
|
|
length++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
buffer = xtrymalloc (length+1);
|
|
|
|
|
if (!buffer)
|
|
|
|
|
return NULL;
|
|
|
|
|
p = buffer;
|
|
|
|
|
for (s=value; *s; s++)
|
|
|
|
|
{
|
|
|
|
|
*p++ = *s;
|
|
|
|
|
if (*s == '&')
|
|
|
|
|
*p++ = '&';
|
|
|
|
|
}
|
|
|
|
|
*p = 0;
|
|
|
|
|
return buffer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Parse PATTERN and return a new filter expression for an LDAP query.
|
|
|
|
|
* The extended filter syntax as known by dirmngr_ldap.c is used.
|
|
|
|
|
* Caller must release the returned value. R_RESULT is set to NULL on
|
|
|
|
|
* error.
|
|
|
|
|
*
|
|
|
|
|
* Supported patterns:
|
2010-06-09 16:53:51 +00:00
|
|
|
|
*
|
2021-06-08 08:46:59 +02:00
|
|
|
|
* | Ok | gpg style user id type |
|
|
|
|
|
* |-----+------------------------------------------------------|
|
|
|
|
|
* | no | KeyID |
|
|
|
|
|
* | no | Fingerprint |
|
|
|
|
|
* | no | OpenPGP userid |
|
|
|
|
|
* | yes | Email address Indicated by a left angle bracket. |
|
|
|
|
|
* | no | Exact word match in user id or subj. name |
|
|
|
|
|
* | yes | Subj. DN indicated by a leading slash |
|
|
|
|
|
* | no | Issuer DN |
|
|
|
|
|
* | no | Serial number + subj. DN |
|
|
|
|
|
* | yes | Substring match indicated by a leading '*; (default) |
|
2010-06-09 16:53:51 +00:00
|
|
|
|
*/
|
2021-06-08 08:46:59 +02:00
|
|
|
|
static gpg_error_t
|
|
|
|
|
make_one_filter (const char *pattern, char **r_result)
|
2010-06-09 16:53:51 +00:00
|
|
|
|
{
|
2021-06-08 08:46:59 +02:00
|
|
|
|
gpg_error_t err = 0;
|
|
|
|
|
char *pattern_buffer = NULL;
|
|
|
|
|
char *result = NULL;
|
|
|
|
|
size_t n;
|
|
|
|
|
|
|
|
|
|
*r_result = NULL;
|
2010-06-09 16:53:51 +00:00
|
|
|
|
|
|
|
|
|
switch (*pattern)
|
|
|
|
|
{
|
|
|
|
|
case '<': /* Email. */
|
|
|
|
|
{
|
|
|
|
|
pattern++;
|
2021-06-08 08:46:59 +02:00
|
|
|
|
if (rfc2254_need_escape (pattern)
|
|
|
|
|
&& !(pattern = pattern_buffer = rfc2254_escape (pattern)))
|
2010-06-09 16:53:51 +00:00
|
|
|
|
{
|
2021-06-08 08:46:59 +02:00
|
|
|
|
err = gpg_error_from_syserror ();
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
result = strconcat ("(mail=", pattern, ")", NULL);
|
|
|
|
|
if (!result)
|
|
|
|
|
{
|
|
|
|
|
err = gpg_error_from_syserror ();
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
n = strlen (result);
|
|
|
|
|
if (result[n-2] == '>') /* Strip trailing '>' */
|
|
|
|
|
{
|
|
|
|
|
result[n-2] = ')';
|
|
|
|
|
result[n-1] = 0;
|
2010-06-09 16:53:51 +00:00
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case '/': /* Subject DN. */
|
|
|
|
|
pattern++;
|
|
|
|
|
if (*pattern)
|
|
|
|
|
{
|
2021-06-08 08:46:59 +02:00
|
|
|
|
/* We need just the BaseDN. This assumes that the Subject
|
|
|
|
|
* is correcly stored in the DT. This is however not always
|
|
|
|
|
* the case and the actual DN is different ffrom the
|
|
|
|
|
* subject. In this case we won't find anything. */
|
|
|
|
|
if (extfilt_need_escape (pattern)
|
|
|
|
|
&& !(pattern = pattern_buffer = extfilt_escape (pattern)))
|
|
|
|
|
{
|
|
|
|
|
err = gpg_error_from_syserror ();
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
result = strconcat ("^", pattern, "&base&", NULL);
|
|
|
|
|
if (!result)
|
|
|
|
|
{
|
|
|
|
|
err = gpg_error_from_syserror ();
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
2010-06-09 16:53:51 +00:00
|
|
|
|
}
|
|
|
|
|
break;
|
2021-06-08 08:46:59 +02:00
|
|
|
|
case '#': /* Issuer DN - Not yet working. */
|
2010-06-09 16:53:51 +00:00
|
|
|
|
pattern++;
|
|
|
|
|
if (*pattern == '/') /* Just issuer DN. */
|
|
|
|
|
{
|
|
|
|
|
pattern++;
|
2021-06-08 08:46:59 +02:00
|
|
|
|
if (extfilt_need_escape (pattern)
|
|
|
|
|
&& !(pattern = pattern_buffer = extfilt_escape (pattern)))
|
|
|
|
|
{
|
|
|
|
|
err = gpg_error_from_syserror ();
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
result = strconcat ("^", pattern, "&base&", NULL);
|
|
|
|
|
if (!result)
|
|
|
|
|
{
|
|
|
|
|
err = gpg_error_from_syserror ();
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
2010-06-09 16:53:51 +00:00
|
|
|
|
}
|
|
|
|
|
else /* Serial number + issuer DN */
|
|
|
|
|
{
|
2021-06-08 08:46:59 +02:00
|
|
|
|
|
2010-06-09 16:53:51 +00:00
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case '*':
|
|
|
|
|
pattern++;
|
2017-07-24 15:35:34 +09:00
|
|
|
|
/* fall through */
|
2010-06-09 16:53:51 +00:00
|
|
|
|
default: /* Take as substring match. */
|
2021-06-08 08:46:59 +02:00
|
|
|
|
if (*pattern)
|
|
|
|
|
{
|
|
|
|
|
if (rfc2254_need_escape (pattern)
|
|
|
|
|
&& !(pattern = pattern_buffer = rfc2254_escape (pattern)))
|
|
|
|
|
{
|
|
|
|
|
err = gpg_error_from_syserror ();
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
result = strconcat ("(|(sn=*", pattern,
|
|
|
|
|
"*)(|(cn=*", pattern,
|
|
|
|
|
"*)(mail=*", pattern,
|
|
|
|
|
"*)))", NULL);
|
|
|
|
|
if (!result)
|
|
|
|
|
{
|
|
|
|
|
err = gpg_error_from_syserror ();
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-06-09 16:53:51 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2021-06-08 08:46:59 +02:00
|
|
|
|
if (!result)
|
|
|
|
|
err = gpg_error (GPG_ERR_INV_USER_ID);
|
2010-06-09 16:53:51 +00:00
|
|
|
|
|
2021-06-08 08:46:59 +02:00
|
|
|
|
leave:
|
|
|
|
|
xfree (pattern_buffer);
|
|
|
|
|
if (err)
|
|
|
|
|
xfree (result);
|
2017-02-16 10:19:59 +01:00
|
|
|
|
else
|
2021-06-08 08:46:59 +02:00
|
|
|
|
*r_result = result;
|
2017-02-16 10:19:59 +01:00
|
|
|
|
return err;
|
2010-06-09 16:53:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2021-06-08 08:46:59 +02:00
|
|
|
|
|
2020-10-05 17:21:55 +02:00
|
|
|
|
/* Prepare an LDAP query to return the cACertificate attribute for DN.
|
|
|
|
|
* All configured default servers are queried until one responds.
|
|
|
|
|
* This function returns an error code or 0 and stored a newly
|
|
|
|
|
* allocated contect object at CONTEXT on success. */
|
2010-06-09 16:53:51 +00:00
|
|
|
|
gpg_error_t
|
2020-10-05 17:21:55 +02:00
|
|
|
|
start_cacert_fetch_ldap (ctrl_t ctrl, cert_fetch_context_t *r_context,
|
|
|
|
|
const char *dn)
|
2010-06-09 16:53:51 +00:00
|
|
|
|
{
|
|
|
|
|
gpg_error_t err;
|
|
|
|
|
struct ldapserver_iter iter;
|
|
|
|
|
|
2020-10-05 17:21:55 +02:00
|
|
|
|
*r_context = xtrycalloc (1, sizeof **r_context);
|
|
|
|
|
if (!*r_context)
|
2010-06-09 16:53:51 +00:00
|
|
|
|
return gpg_error_from_errno (errno);
|
|
|
|
|
|
2021-06-08 08:46:59 +02:00
|
|
|
|
/* FIXME; we might want to look at the Base DN to try matching
|
2010-06-09 16:53:51 +00:00
|
|
|
|
servers first. */
|
|
|
|
|
err = gpg_error (GPG_ERR_CONFIGURATION);
|
|
|
|
|
|
|
|
|
|
for (ldapserver_iter_begin (&iter, ctrl); ! ldapserver_iter_end_p (&iter);
|
|
|
|
|
ldapserver_iter_next (&iter))
|
|
|
|
|
{
|
|
|
|
|
ldap_server_t server = iter.server;
|
|
|
|
|
|
|
|
|
|
err = run_ldap_wrapper (ctrl,
|
|
|
|
|
0,
|
2020-10-05 17:21:55 +02:00
|
|
|
|
1, /* --multi (record format) */
|
2021-06-08 08:46:59 +02:00
|
|
|
|
0, /* No TLS */
|
|
|
|
|
0, /* No AD authentication. */
|
2010-06-09 16:53:51 +00:00
|
|
|
|
opt.ldap_proxy,
|
|
|
|
|
server->host, server->port,
|
|
|
|
|
server->user, server->pass,
|
2021-06-08 08:46:59 +02:00
|
|
|
|
dn, "objectClass=*", "cACertificate",
|
2020-10-05 17:21:55 +02:00
|
|
|
|
&(*r_context)->reader);
|
2010-06-09 16:53:51 +00:00
|
|
|
|
if (!err)
|
|
|
|
|
break; /* Probably found a result. */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (err)
|
|
|
|
|
{
|
2020-10-05 17:21:55 +02:00
|
|
|
|
xfree (*r_context);
|
|
|
|
|
*r_context = NULL;
|
2010-06-09 16:53:51 +00:00
|
|
|
|
}
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2020-10-05 17:21:55 +02:00
|
|
|
|
/* Prepare an LDAP query to return certificates matching PATTERNS
|
|
|
|
|
* using the SERVER. This function returns an error code or 0 and
|
|
|
|
|
* stores a newly allocated object at R_CONTEXT on success. */
|
2010-06-09 16:53:51 +00:00
|
|
|
|
gpg_error_t
|
2020-10-05 17:21:55 +02:00
|
|
|
|
start_cert_fetch_ldap (ctrl_t ctrl, cert_fetch_context_t *r_context,
|
2010-06-09 16:53:51 +00:00
|
|
|
|
strlist_t patterns, const ldap_server_t server)
|
|
|
|
|
{
|
|
|
|
|
gpg_error_t err;
|
2015-11-27 17:10:59 +01:00
|
|
|
|
char *proxy = NULL;
|
|
|
|
|
char *host = NULL;
|
2010-06-09 16:53:51 +00:00
|
|
|
|
int port;
|
2015-11-27 17:10:59 +01:00
|
|
|
|
char *user = NULL;
|
|
|
|
|
char *pass = NULL;
|
2021-06-08 08:46:59 +02:00
|
|
|
|
char *base = NULL;
|
2015-11-19 16:45:09 +01:00
|
|
|
|
char *argv[50];
|
2015-11-27 17:10:59 +01:00
|
|
|
|
int argc = 0;
|
|
|
|
|
int argc_malloced = 0;
|
2010-06-09 16:53:51 +00:00
|
|
|
|
char portbuf[30], timeoutbuf[30];
|
2021-06-08 08:46:59 +02:00
|
|
|
|
int starttls, ldaptls, ntds;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2020-10-05 17:21:55 +02:00
|
|
|
|
*r_context = NULL;
|
2015-11-27 17:10:59 +01:00
|
|
|
|
|
|
|
|
|
if (opt.ldap_proxy && !(proxy = xtrystrdup (opt.ldap_proxy)))
|
|
|
|
|
{
|
|
|
|
|
err = gpg_error_from_syserror ();
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-09 16:53:51 +00:00
|
|
|
|
if (server)
|
|
|
|
|
{
|
2015-11-27 17:10:59 +01:00
|
|
|
|
if (server->host && !(host = xtrystrdup (server->host)))
|
|
|
|
|
{
|
|
|
|
|
err = gpg_error_from_syserror ();
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
2010-06-09 16:53:51 +00:00
|
|
|
|
port = server->port;
|
2015-11-27 17:10:59 +01:00
|
|
|
|
if (server->user && !(user = xtrystrdup (server->user)))
|
|
|
|
|
{
|
|
|
|
|
err = gpg_error_from_syserror ();
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
if (server->pass && !(pass = xtrystrdup (server->pass)))
|
|
|
|
|
{
|
|
|
|
|
err = gpg_error_from_syserror ();
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
2021-06-08 08:46:59 +02:00
|
|
|
|
if (server->base && !(base = xtrystrdup (server->base)))
|
|
|
|
|
{
|
|
|
|
|
err = gpg_error_from_syserror ();
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
starttls = server->starttls;
|
|
|
|
|
ldaptls = server->ldap_over_tls;
|
|
|
|
|
ntds = server->ntds;
|
2010-06-09 16:53:51 +00:00
|
|
|
|
}
|
|
|
|
|
else /* Use a default server. */
|
2021-05-20 10:13:51 +02:00
|
|
|
|
{
|
2021-06-08 08:46:59 +02:00
|
|
|
|
err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
|
|
|
|
|
goto leave;
|
2021-05-20 10:13:51 +02:00
|
|
|
|
}
|
2015-11-27 17:10:59 +01:00
|
|
|
|
|
2010-06-09 16:53:51 +00:00
|
|
|
|
|
2021-06-08 08:46:59 +02:00
|
|
|
|
if (pass && *pass) /* Note: Must be the first item. */
|
2010-06-09 16:53:51 +00:00
|
|
|
|
{
|
|
|
|
|
argv[argc++] = "--pass";
|
|
|
|
|
argv[argc++] = pass;
|
|
|
|
|
}
|
2018-04-27 11:57:08 +02:00
|
|
|
|
|
|
|
|
|
if (DBG_LOOKUP)
|
2010-06-09 16:53:51 +00:00
|
|
|
|
argv[argc++] = "-vv";
|
2018-04-27 11:57:08 +02:00
|
|
|
|
else if (DBG_EXTPROG)
|
|
|
|
|
argv[argc++] = "-v";
|
|
|
|
|
|
2010-06-09 16:53:51 +00:00
|
|
|
|
argv[argc++] = "--log-with-pid";
|
|
|
|
|
argv[argc++] = "--multi";
|
2021-06-08 08:46:59 +02:00
|
|
|
|
|
|
|
|
|
if (starttls)
|
|
|
|
|
argv[argc++] = "--starttls";
|
|
|
|
|
else if (ldaptls)
|
|
|
|
|
argv[argc++] = "--ldaptls";
|
|
|
|
|
|
|
|
|
|
if (ntds)
|
|
|
|
|
argv[argc++] = "--ntds";
|
|
|
|
|
|
2010-06-09 16:53:51 +00:00
|
|
|
|
if (opt.ldaptimeout)
|
|
|
|
|
{
|
2015-11-27 17:10:59 +01:00
|
|
|
|
snprintf (timeoutbuf, sizeof timeoutbuf, "%u", opt.ldaptimeout);
|
2010-06-09 16:53:51 +00:00
|
|
|
|
argv[argc++] = "--timeout";
|
|
|
|
|
argv[argc++] = timeoutbuf;
|
|
|
|
|
}
|
2021-06-08 08:46:59 +02:00
|
|
|
|
if (proxy && *proxy)
|
2010-06-09 16:53:51 +00:00
|
|
|
|
{
|
|
|
|
|
argv[argc++] = "--proxy";
|
2015-11-27 17:10:59 +01:00
|
|
|
|
argv[argc++] = proxy;
|
2010-06-09 16:53:51 +00:00
|
|
|
|
}
|
2021-06-08 08:46:59 +02:00
|
|
|
|
if (host && *host)
|
2010-06-09 16:53:51 +00:00
|
|
|
|
{
|
|
|
|
|
argv[argc++] = "--host";
|
|
|
|
|
argv[argc++] = host;
|
|
|
|
|
}
|
|
|
|
|
if (port)
|
|
|
|
|
{
|
2015-11-27 17:10:59 +01:00
|
|
|
|
snprintf (portbuf, sizeof portbuf, "%d", port);
|
2010-06-09 16:53:51 +00:00
|
|
|
|
argv[argc++] = "--port";
|
|
|
|
|
argv[argc++] = portbuf;
|
|
|
|
|
}
|
2021-06-08 08:46:59 +02:00
|
|
|
|
if (user && *user)
|
2010-06-09 16:53:51 +00:00
|
|
|
|
{
|
|
|
|
|
argv[argc++] = "--user";
|
|
|
|
|
argv[argc++] = user;
|
|
|
|
|
}
|
2021-06-08 08:46:59 +02:00
|
|
|
|
if (base && *base)
|
|
|
|
|
{
|
|
|
|
|
argv[argc++] = "--base";
|
|
|
|
|
argv[argc++] = base;
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-09 16:53:51 +00:00
|
|
|
|
|
2015-11-19 16:45:09 +01:00
|
|
|
|
/* All entries in argv from this index on are malloc'ed. */
|
|
|
|
|
argc_malloced = argc;
|
2010-06-09 16:53:51 +00:00
|
|
|
|
|
|
|
|
|
for (; patterns; patterns = patterns->next)
|
|
|
|
|
{
|
2015-01-07 16:56:43 +09:00
|
|
|
|
if (argc >= DIM (argv) - 1)
|
2010-06-09 16:53:51 +00:00
|
|
|
|
{
|
|
|
|
|
/* Too many patterns. It does not make sense to allow an
|
|
|
|
|
arbitrary number of patters because the length of the
|
|
|
|
|
command line is limited anyway. */
|
2021-06-08 08:46:59 +02:00
|
|
|
|
err = gpg_error (GPG_ERR_RESOURCE_LIMIT);
|
|
|
|
|
goto leave;
|
2010-06-09 16:53:51 +00:00
|
|
|
|
}
|
2021-06-08 08:46:59 +02:00
|
|
|
|
if (*patterns->d)
|
2010-06-09 16:53:51 +00:00
|
|
|
|
{
|
2021-06-08 08:46:59 +02:00
|
|
|
|
err = make_one_filter (patterns->d, &argv[argc]);
|
|
|
|
|
if (err)
|
|
|
|
|
goto leave;
|
|
|
|
|
argc++;
|
2010-06-09 16:53:51 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
argv[argc] = NULL;
|
|
|
|
|
|
2020-10-05 17:21:55 +02:00
|
|
|
|
*r_context = xtrycalloc (1, sizeof **r_context);
|
|
|
|
|
if (!*r_context)
|
2015-11-19 16:45:09 +01:00
|
|
|
|
{
|
2021-06-08 08:46:59 +02:00
|
|
|
|
err = gpg_error_from_syserror ();
|
2015-11-19 16:45:09 +01:00
|
|
|
|
goto leave;
|
|
|
|
|
}
|
2010-06-09 16:53:51 +00:00
|
|
|
|
|
2020-10-05 17:21:55 +02:00
|
|
|
|
err = ldap_wrapper (ctrl, &(*r_context)->reader, (const char**)argv);
|
2010-06-09 16:53:51 +00:00
|
|
|
|
if (err)
|
|
|
|
|
{
|
2020-10-05 17:21:55 +02:00
|
|
|
|
xfree (*r_context);
|
|
|
|
|
*r_context = NULL;
|
2010-06-09 16:53:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
2015-11-19 16:45:09 +01:00
|
|
|
|
leave:
|
|
|
|
|
for (; argc_malloced < argc; argc_malloced++)
|
|
|
|
|
xfree (argv[argc_malloced]);
|
2015-11-27 17:10:59 +01:00
|
|
|
|
xfree (proxy);
|
|
|
|
|
xfree (host);
|
2021-06-08 08:46:59 +02:00
|
|
|
|
xfree (base);
|
2015-11-27 17:10:59 +01:00
|
|
|
|
xfree (user);
|
|
|
|
|
xfree (pass);
|
2010-06-09 16:53:51 +00:00
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Read a fixed amount of data from READER into BUFFER. */
|
|
|
|
|
static gpg_error_t
|
|
|
|
|
read_buffer (ksba_reader_t reader, unsigned char *buffer, size_t count)
|
|
|
|
|
{
|
|
|
|
|
gpg_error_t err;
|
|
|
|
|
size_t nread;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2010-06-09 16:53:51 +00:00
|
|
|
|
while (count)
|
|
|
|
|
{
|
|
|
|
|
err = ksba_reader_read (reader, buffer, count, &nread);
|
|
|
|
|
if (err)
|
|
|
|
|
return err;
|
|
|
|
|
buffer += nread;
|
|
|
|
|
count -= nread;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Fetch the next certificate. Return 0 on success, GPG_ERR_EOF if no
|
|
|
|
|
(more) certificates are available or any other error
|
|
|
|
|
code. GPG_ERR_TRUNCATED may be returned to indicate that the result
|
|
|
|
|
has been truncated. */
|
|
|
|
|
gpg_error_t
|
|
|
|
|
fetch_next_cert_ldap (cert_fetch_context_t context,
|
|
|
|
|
unsigned char **value, size_t *valuelen)
|
|
|
|
|
{
|
|
|
|
|
gpg_error_t err;
|
|
|
|
|
unsigned char hdr[5];
|
|
|
|
|
char *p, *pend;
|
2015-02-11 10:27:57 +01:00
|
|
|
|
unsigned long n;
|
2010-06-09 16:53:51 +00:00
|
|
|
|
int okay = 0;
|
2011-11-24 15:48:24 +01:00
|
|
|
|
/* int is_cms = 0; */
|
2010-06-09 16:53:51 +00:00
|
|
|
|
|
|
|
|
|
*value = NULL;
|
|
|
|
|
*valuelen = 0;
|
|
|
|
|
|
|
|
|
|
err = 0;
|
|
|
|
|
while (!err)
|
|
|
|
|
{
|
|
|
|
|
err = read_buffer (context->reader, hdr, 5);
|
|
|
|
|
if (err)
|
|
|
|
|
break;
|
2015-02-11 10:27:57 +01:00
|
|
|
|
n = buf32_to_ulong (hdr+1);
|
2010-06-09 16:53:51 +00:00
|
|
|
|
if (*hdr == 'V' && okay)
|
|
|
|
|
{
|
2020-10-05 17:21:55 +02:00
|
|
|
|
#if 0 /* That code to extra a cert from a CMS object is not yet ready. */
|
2010-06-09 16:53:51 +00:00
|
|
|
|
if (is_cms)
|
|
|
|
|
{
|
|
|
|
|
/* The certificate needs to be parsed from CMS data. */
|
|
|
|
|
ksba_cms_t cms;
|
|
|
|
|
ksba_stop_reason_t stopreason;
|
|
|
|
|
int i;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2010-06-09 16:53:51 +00:00
|
|
|
|
err = ksba_cms_new (&cms);
|
|
|
|
|
if (err)
|
|
|
|
|
goto leave;
|
|
|
|
|
err = ksba_cms_set_reader_writer (cms, context->reader, NULL);
|
|
|
|
|
if (err)
|
|
|
|
|
{
|
|
|
|
|
log_error ("ksba_cms_set_reader_writer failed: %s\n",
|
|
|
|
|
gpg_strerror (err));
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-04 12:57:53 +01:00
|
|
|
|
do
|
2010-06-09 16:53:51 +00:00
|
|
|
|
{
|
|
|
|
|
err = ksba_cms_parse (cms, &stopreason);
|
|
|
|
|
if (err)
|
|
|
|
|
{
|
|
|
|
|
log_error ("ksba_cms_parse failed: %s\n",
|
|
|
|
|
gpg_strerror (err));
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (stopreason == KSBA_SR_BEGIN_DATA)
|
|
|
|
|
log_error ("userSMIMECertificate is not "
|
|
|
|
|
"a certs-only message\n");
|
|
|
|
|
}
|
2011-02-04 12:57:53 +01:00
|
|
|
|
while (stopreason != KSBA_SR_READY);
|
|
|
|
|
|
2010-06-09 16:53:51 +00:00
|
|
|
|
for (i=0; (cert=ksba_cms_get_cert (cms, i)); i++)
|
|
|
|
|
{
|
|
|
|
|
check_and_store (ctrl, stats, cert, 0);
|
2011-02-04 12:57:53 +01:00
|
|
|
|
ksba_cert_release (cert);
|
2010-06-09 16:53:51 +00:00
|
|
|
|
cert = NULL;
|
|
|
|
|
}
|
|
|
|
|
if (!i)
|
|
|
|
|
log_error ("no certificate found\n");
|
|
|
|
|
else
|
|
|
|
|
any = 1;
|
|
|
|
|
}
|
|
|
|
|
else
|
2020-10-05 17:21:55 +02:00
|
|
|
|
#endif /* End unfinished code to extract from a CMS object. */
|
2010-06-09 16:53:51 +00:00
|
|
|
|
{
|
|
|
|
|
*value = xtrymalloc (n);
|
|
|
|
|
if (!*value)
|
|
|
|
|
return gpg_error_from_errno (errno);
|
2011-02-04 12:57:53 +01:00
|
|
|
|
*valuelen = n;
|
2010-06-09 16:53:51 +00:00
|
|
|
|
err = read_buffer (context->reader, *value, n);
|
|
|
|
|
break; /* Ready or error. */
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (!n && *hdr == 'A')
|
|
|
|
|
okay = 0;
|
|
|
|
|
else if (n)
|
|
|
|
|
{
|
|
|
|
|
if (n > context->tmpbufsize)
|
|
|
|
|
{
|
|
|
|
|
xfree (context->tmpbuf);
|
|
|
|
|
context->tmpbufsize = 0;
|
|
|
|
|
context->tmpbuf = xtrymalloc (n+1);
|
|
|
|
|
if (!context->tmpbuf)
|
|
|
|
|
return gpg_error_from_errno (errno);
|
|
|
|
|
context->tmpbufsize = n;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
}
|
2010-06-09 16:53:51 +00:00
|
|
|
|
err = read_buffer (context->reader, context->tmpbuf, n);
|
|
|
|
|
if (err)
|
|
|
|
|
break;
|
|
|
|
|
if (*hdr == 'A')
|
|
|
|
|
{
|
|
|
|
|
p = context->tmpbuf;
|
|
|
|
|
p[n] = 0; /*(we allocated one extra byte for this.)*/
|
2011-11-24 15:48:24 +01:00
|
|
|
|
/* fixme: is_cms = 0; */
|
2010-06-09 16:53:51 +00:00
|
|
|
|
if ( (pend = strchr (p, ';')) )
|
|
|
|
|
*pend = 0; /* Strip off the extension. */
|
|
|
|
|
if (!ascii_strcasecmp (p, USERCERTIFICATE))
|
|
|
|
|
{
|
|
|
|
|
if (DBG_LOOKUP)
|
2012-06-05 19:29:22 +02:00
|
|
|
|
log_debug ("fetch_next_cert_ldap: got attribute '%s'\n",
|
2010-06-09 16:53:51 +00:00
|
|
|
|
USERCERTIFICATE);
|
|
|
|
|
okay = 1;
|
|
|
|
|
}
|
|
|
|
|
else if (!ascii_strcasecmp (p, CACERTIFICATE))
|
|
|
|
|
{
|
|
|
|
|
if (DBG_LOOKUP)
|
2012-06-05 19:29:22 +02:00
|
|
|
|
log_debug ("fetch_next_cert_ldap: got attribute '%s'\n",
|
2010-06-09 16:53:51 +00:00
|
|
|
|
CACERTIFICATE);
|
|
|
|
|
okay = 1;
|
|
|
|
|
}
|
|
|
|
|
else if (!ascii_strcasecmp (p, X509CACERT))
|
|
|
|
|
{
|
|
|
|
|
if (DBG_LOOKUP)
|
2012-06-05 19:29:22 +02:00
|
|
|
|
log_debug ("fetch_next_cert_ldap: got attribute '%s'\n",
|
2010-06-09 16:53:51 +00:00
|
|
|
|
CACERTIFICATE);
|
|
|
|
|
okay = 1;
|
|
|
|
|
}
|
|
|
|
|
/* else if (!ascii_strcasecmp (p, USERSMIMECERTIFICATE)) */
|
|
|
|
|
/* { */
|
|
|
|
|
/* if (DBG_LOOKUP) */
|
2012-06-05 19:29:22 +02:00
|
|
|
|
/* log_debug ("fetch_next_cert_ldap: got attribute '%s'\n", */
|
2010-06-09 16:53:51 +00:00
|
|
|
|
/* USERSMIMECERTIFICATE); */
|
|
|
|
|
/* okay = 1; */
|
|
|
|
|
/* is_cms = 1; */
|
|
|
|
|
/* } */
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (DBG_LOOKUP)
|
2012-06-05 19:29:22 +02:00
|
|
|
|
log_debug ("fetch_next_cert_ldap: got attribute '%s'"
|
2010-06-09 16:53:51 +00:00
|
|
|
|
" - ignored\n", p);
|
|
|
|
|
okay = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (*hdr == 'E')
|
|
|
|
|
{
|
|
|
|
|
p = context->tmpbuf;
|
|
|
|
|
p[n] = 0; /*(we allocated one extra byte for this.)*/
|
|
|
|
|
if (!strcmp (p, "truncated"))
|
|
|
|
|
{
|
|
|
|
|
context->truncated = 1;
|
|
|
|
|
log_info (_("ldap_search hit the size limit of"
|
|
|
|
|
" the server\n"));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (err)
|
|
|
|
|
{
|
|
|
|
|
xfree (*value);
|
|
|
|
|
*value = NULL;
|
|
|
|
|
*valuelen = 0;
|
|
|
|
|
if (gpg_err_code (err) == GPG_ERR_EOF && context->truncated)
|
|
|
|
|
{
|
|
|
|
|
context->truncated = 0; /* So that the next call would return EOF. */
|
|
|
|
|
err = gpg_error (GPG_ERR_TRUNCATED);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
end_cert_fetch_ldap (cert_fetch_context_t context)
|
|
|
|
|
{
|
|
|
|
|
if (context)
|
|
|
|
|
{
|
|
|
|
|
ksba_reader_t reader = context->reader;
|
|
|
|
|
|
|
|
|
|
xfree (context->tmpbuf);
|
|
|
|
|
xfree (context);
|
|
|
|
|
ldap_wrapper_release_context (reader);
|
|
|
|
|
ksba_reader_release (reader);
|
|
|
|
|
}
|
|
|
|
|
}
|