mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
096e7457ec
The asymmetric quotes used by GNU in the past (`...') don't render nicely on modern systems. We now use two \x27 characters ('...'). The proper solution would be to use the correct Unicode symmetric quotes here. However this has the disadvantage that the system requires Unicode support. We don't want that today. If Unicode is available a generated po file can be used to output proper quotes. A simple sed script like the one used for en@quote is sufficient to change them. The changes have been done by applying sed -i "s/\`\([^'\`]*\)'/'\1'/g" to most files and fixing obvious problems by hand. The msgid strings in the po files were fixed with a similar command.
844 lines
22 KiB
C
844 lines
22 KiB
C
/* ldap.c - LDAP access
|
||
* Copyright (C) 2002 Klarälvdalens Datakonsult AB
|
||
* Copyright (C) 2003, 2004, 2005, 2007, 2008, 2010 g10 Code GmbH
|
||
*
|
||
* This file is part of DirMngr.
|
||
*
|
||
* DirMngr is free software; you can redistribute it and/or modify
|
||
* it under the terms of the GNU General Public License as published by
|
||
* the Free Software Foundation; either version 2 of the License, or
|
||
* (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
|
||
* along with this program; if not, write to the Free Software
|
||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||
*/
|
||
|
||
#include <config.h>
|
||
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
#include <errno.h>
|
||
#include <unistd.h>
|
||
#include <fcntl.h>
|
||
#include <time.h>
|
||
#include <npth.h>
|
||
|
||
#include "dirmngr.h"
|
||
#include "exechelp.h"
|
||
#include "crlfetch.h"
|
||
#include "ldapserver.h"
|
||
#include "misc.h"
|
||
#include "ldap-wrapper.h"
|
||
|
||
|
||
#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;
|
||
}
|
||
|
||
log_info (_("adding '%s:%d' to the ldap server list\n"), host, port);
|
||
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
|
||
run_ldap_wrapper (ctrl_t ctrl,
|
||
int ignore_timeout,
|
||
int multi_mode,
|
||
const char *proxy,
|
||
const char *host, int port,
|
||
const char *user, const char *pass,
|
||
const char *dn, const char *filter, const char *attr,
|
||
const char *url,
|
||
ksba_reader_t *reader)
|
||
{
|
||
const char *argv[40];
|
||
int argc;
|
||
char portbuf[30], timeoutbuf[30];
|
||
|
||
|
||
*reader = NULL;
|
||
|
||
argc = 0;
|
||
if (pass) /* Note, that the password most be the first item. */
|
||
{
|
||
argv[argc++] = "--pass";
|
||
argv[argc++] = pass;
|
||
}
|
||
if (opt.verbose)
|
||
argv[argc++] = "-vv";
|
||
argv[argc++] = "--log-with-pid";
|
||
if (multi_mode)
|
||
argv[argc++] = "--multi";
|
||
if (opt.ldaptimeout)
|
||
{
|
||
sprintf (timeoutbuf, "%u", opt.ldaptimeout);
|
||
argv[argc++] = "--timeout";
|
||
argv[argc++] = timeoutbuf;
|
||
if (ignore_timeout)
|
||
argv[argc++] = "--only-search-timeout";
|
||
}
|
||
if (proxy)
|
||
{
|
||
argv[argc++] = "--proxy";
|
||
argv[argc++] = proxy;
|
||
}
|
||
if (host)
|
||
{
|
||
argv[argc++] = "--host";
|
||
argv[argc++] = host;
|
||
}
|
||
if (port)
|
||
{
|
||
sprintf (portbuf, "%d", port);
|
||
argv[argc++] = "--port";
|
||
argv[argc++] = portbuf;
|
||
}
|
||
if (user)
|
||
{
|
||
argv[argc++] = "--user";
|
||
argv[argc++] = user;
|
||
}
|
||
if (dn)
|
||
{
|
||
argv[argc++] = "--dn";
|
||
argv[argc++] = dn;
|
||
}
|
||
if (filter)
|
||
{
|
||
argv[argc++] = "--filter";
|
||
argv[argc++] = filter;
|
||
}
|
||
if (attr)
|
||
{
|
||
argv[argc++] = "--attr";
|
||
argv[argc++] = attr;
|
||
}
|
||
argv[argc++] = url? url : "ldap://";
|
||
argv[argc] = NULL;
|
||
|
||
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
|
||
url_fetch_ldap (ctrl_t ctrl, const char *url, const char *host, int port,
|
||
ksba_reader_t *reader)
|
||
{
|
||
gpg_error_t err;
|
||
|
||
err = run_ldap_wrapper (ctrl,
|
||
1, /* Ignore explicit timeout because CRLs
|
||
might be very large. */
|
||
0,
|
||
opt.ldap_proxy,
|
||
host, port,
|
||
NULL, NULL,
|
||
NULL, NULL, NULL, url,
|
||
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. */
|
||
if (!err && opt.add_new_ldapservers && !opt.ldap_proxy)
|
||
{
|
||
if (host)
|
||
add_server_to_servers (host, port);
|
||
else if (url)
|
||
{
|
||
char *tmp = host_and_port_from_url (url, &port);
|
||
if (tmp)
|
||
{
|
||
add_server_to_servers (tmp, port);
|
||
xfree (tmp);
|
||
}
|
||
}
|
||
}
|
||
|
||
/* 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;
|
||
|
||
if (DBG_LOOKUP)
|
||
log_debug ("no hostname in URL or query failed; "
|
||
"trying all default hostnames\n");
|
||
|
||
for (ldapserver_iter_begin (&iter, ctrl);
|
||
err && ! ldapserver_iter_end_p (&iter);
|
||
ldapserver_iter_next (&iter))
|
||
{
|
||
ldap_server_t server = iter.server;
|
||
|
||
err = run_ldap_wrapper (ctrl,
|
||
0,
|
||
0,
|
||
NULL,
|
||
server->host, server->port,
|
||
NULL, NULL,
|
||
NULL, NULL, NULL, url,
|
||
reader);
|
||
if (!err)
|
||
break;
|
||
}
|
||
}
|
||
|
||
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;
|
||
|
||
/* FIXME; we might want to look at the Base SN to try matching
|
||
servers first. */
|
||
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,
|
||
0,
|
||
opt.ldap_proxy,
|
||
server->host, server->port,
|
||
server->user, server->pass,
|
||
dn, "objectClass=*", attr, NULL,
|
||
reader);
|
||
if (!err)
|
||
break; /* Probably found a result. Ready. */
|
||
}
|
||
return err;
|
||
}
|
||
|
||
|
||
/* Parse PATTERN and return a new strlist to be used for the actual
|
||
LDAP query. Bit 0 of the flags field is set if that pattern is
|
||
actually a base specification. Caller must release the returned
|
||
strlist. NULL is returned on error.
|
||
|
||
* Possible patterns:
|
||
*
|
||
* KeyID
|
||
* Fingerprint
|
||
* OpenPGP userid
|
||
* x Email address Indicated by a left angle bracket.
|
||
* Exact word match in user id or subj. name
|
||
* x Subj. DN indicated bu a leading slash
|
||
* Issuer DN
|
||
* Serial number + subj. DN
|
||
* x Substring match indicated by a leading '*; is also the default.
|
||
*/
|
||
|
||
strlist_t
|
||
parse_one_pattern (const char *pattern)
|
||
{
|
||
strlist_t result = NULL;
|
||
char *p;
|
||
|
||
switch (*pattern)
|
||
{
|
||
case '<': /* Email. */
|
||
{
|
||
pattern++;
|
||
result = xmalloc (sizeof *result + 5 + strlen (pattern));
|
||
result->next = NULL;
|
||
result->flags = 0;
|
||
p = stpcpy (stpcpy (result->d, "mail="), pattern);
|
||
if (p[-1] == '>')
|
||
*--p = 0;
|
||
if (!*result->d) /* Error. */
|
||
{
|
||
xfree (result);
|
||
result = NULL;
|
||
}
|
||
break;
|
||
}
|
||
case '/': /* Subject DN. */
|
||
pattern++;
|
||
if (*pattern)
|
||
{
|
||
result = xmalloc (sizeof *result + strlen (pattern));
|
||
result->next = NULL;
|
||
result->flags = 1; /* Base spec. */
|
||
strcpy (result->d, pattern);
|
||
}
|
||
break;
|
||
case '#': /* Issuer DN. */
|
||
pattern++;
|
||
if (*pattern == '/') /* Just issuer DN. */
|
||
{
|
||
pattern++;
|
||
}
|
||
else /* Serial number + issuer DN */
|
||
{
|
||
}
|
||
break;
|
||
case '*':
|
||
pattern++;
|
||
default: /* Take as substring match. */
|
||
{
|
||
const char format[] = "(|(sn=*%s*)(|(cn=*%s*)(mail=*%s*)))";
|
||
|
||
if (*pattern)
|
||
{
|
||
result = xmalloc (sizeof *result
|
||
+ strlen (format) + 3 * strlen (pattern));
|
||
result->next = NULL;
|
||
result->flags = 0;
|
||
sprintf (result->d, format, pattern, pattern, pattern);
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
/* Take the string STRING and escape it accoring to the URL rules.
|
||
Retun a newly allocated string. */
|
||
static char *
|
||
escape4url (const char *string)
|
||
{
|
||
const char *s;
|
||
char *buf, *p;
|
||
size_t n;
|
||
|
||
if (!string)
|
||
string = "";
|
||
|
||
for (s=string,n=0; *s; s++)
|
||
if (strchr (UNENCODED_URL_CHARS, *s))
|
||
n++;
|
||
else
|
||
n += 3;
|
||
|
||
buf = malloc (n+1);
|
||
if (!buf)
|
||
return NULL;
|
||
|
||
for (s=string,p=buf; *s; s++)
|
||
if (strchr (UNENCODED_URL_CHARS, *s))
|
||
*p++ = *s;
|
||
else
|
||
{
|
||
sprintf (p, "%%%02X", *(const unsigned char *)s);
|
||
p += 3;
|
||
}
|
||
*p = 0;
|
||
|
||
return buf;
|
||
}
|
||
|
||
|
||
|
||
/* Create a LDAP URL from DN and FILTER and return it in URL. We don't
|
||
need the host and port because this will be specified using the
|
||
override options. */
|
||
static gpg_error_t
|
||
make_url (char **url, const char *dn, const char *filter)
|
||
{
|
||
gpg_error_t err;
|
||
char *u_dn, *u_filter;
|
||
char const attrs[] = (USERCERTIFICATE ","
|
||
/* USERSMIMECERTIFICATE "," */
|
||
CACERTIFICATE ","
|
||
X509CACERT );
|
||
|
||
*url = NULL;
|
||
|
||
u_dn = escape4url (dn);
|
||
if (!u_dn)
|
||
return gpg_error_from_errno (errno);
|
||
|
||
u_filter = escape4url (filter);
|
||
if (!u_filter)
|
||
{
|
||
err = gpg_error_from_errno (errno);
|
||
xfree (u_dn);
|
||
return err;
|
||
}
|
||
*url = malloc ( 8 + strlen (u_dn)
|
||
+ 1 + strlen (attrs)
|
||
+ 5 + strlen (u_filter) + 1 );
|
||
if (!*url)
|
||
{
|
||
err = gpg_error_from_errno (errno);
|
||
xfree (u_dn);
|
||
xfree (u_filter);
|
||
return err;
|
||
}
|
||
|
||
stpcpy (stpcpy (stpcpy (stpcpy (stpcpy (stpcpy (*url, "ldap:///"),
|
||
u_dn),
|
||
"?"),
|
||
attrs),
|
||
"?sub?"),
|
||
u_filter);
|
||
xfree (u_dn);
|
||
xfree (u_filter);
|
||
return 0;
|
||
}
|
||
|
||
|
||
/* Prepare an LDAP query to return the attribute ATTR for the DN. All
|
||
configured default servers are queried until one responds. This
|
||
function returns an error code or 0 and a CONTEXT on success. */
|
||
gpg_error_t
|
||
start_default_fetch_ldap (ctrl_t ctrl, cert_fetch_context_t *context,
|
||
const char *dn, const char *attr)
|
||
{
|
||
gpg_error_t err;
|
||
struct ldapserver_iter iter;
|
||
|
||
*context = xtrycalloc (1, sizeof **context);
|
||
if (!*context)
|
||
return gpg_error_from_errno (errno);
|
||
|
||
/* FIXME; we might want to look at the Base SN to try matching
|
||
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,
|
||
1,
|
||
opt.ldap_proxy,
|
||
server->host, server->port,
|
||
server->user, server->pass,
|
||
dn, "objectClass=*", attr, NULL,
|
||
&(*context)->reader);
|
||
if (!err)
|
||
break; /* Probably found a result. */
|
||
}
|
||
|
||
if (err)
|
||
{
|
||
xfree (*context);
|
||
*context = NULL;
|
||
}
|
||
return err;
|
||
}
|
||
|
||
|
||
/* Prepare an LDAP query to return certificates maching PATTERNS using
|
||
the SERVER. This function returns an error code or 0 and a CONTEXT
|
||
on success. */
|
||
gpg_error_t
|
||
start_cert_fetch_ldap (ctrl_t ctrl, cert_fetch_context_t *context,
|
||
strlist_t patterns, const ldap_server_t server)
|
||
{
|
||
gpg_error_t err;
|
||
const char *host;
|
||
int port;
|
||
const char *user;
|
||
const char *pass;
|
||
const char *base;
|
||
const char *argv[50];
|
||
int argc;
|
||
char portbuf[30], timeoutbuf[30];
|
||
|
||
|
||
*context = NULL;
|
||
if (server)
|
||
{
|
||
host = server->host;
|
||
port = server->port;
|
||
user = server->user;
|
||
pass = server->pass;
|
||
base = server->base;
|
||
}
|
||
else /* Use a default server. */
|
||
return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
|
||
|
||
if (!base)
|
||
base = "";
|
||
|
||
argc = 0;
|
||
if (pass) /* Note: Must be the first item. */
|
||
{
|
||
argv[argc++] = "--pass";
|
||
argv[argc++] = pass;
|
||
}
|
||
if (opt.verbose)
|
||
argv[argc++] = "-vv";
|
||
argv[argc++] = "--log-with-pid";
|
||
argv[argc++] = "--multi";
|
||
if (opt.ldaptimeout)
|
||
{
|
||
sprintf (timeoutbuf, "%u", opt.ldaptimeout);
|
||
argv[argc++] = "--timeout";
|
||
argv[argc++] = timeoutbuf;
|
||
}
|
||
if (opt.ldap_proxy)
|
||
{
|
||
argv[argc++] = "--proxy";
|
||
argv[argc++] = opt.ldap_proxy;
|
||
}
|
||
if (host)
|
||
{
|
||
argv[argc++] = "--host";
|
||
argv[argc++] = host;
|
||
}
|
||
if (port)
|
||
{
|
||
sprintf (portbuf, "%d", port);
|
||
argv[argc++] = "--port";
|
||
argv[argc++] = portbuf;
|
||
}
|
||
if (user)
|
||
{
|
||
argv[argc++] = "--user";
|
||
argv[argc++] = user;
|
||
}
|
||
|
||
|
||
for (; patterns; patterns = patterns->next)
|
||
{
|
||
strlist_t sl;
|
||
char *url;
|
||
|
||
if (argc >= sizeof argv -1)
|
||
{
|
||
/* 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. */
|
||
/* fixme: cleanup. */
|
||
return gpg_error (GPG_ERR_RESOURCE_LIMIT);
|
||
}
|
||
sl = parse_one_pattern (patterns->d);
|
||
if (!sl)
|
||
{
|
||
log_error (_("start_cert_fetch: invalid pattern '%s'\n"),
|
||
patterns->d);
|
||
/* fixme: cleanup argv. */
|
||
return gpg_error (GPG_ERR_INV_USER_ID);
|
||
}
|
||
if ((sl->flags & 1))
|
||
err = make_url (&url, sl->d, "objectClass=*");
|
||
else
|
||
err = make_url (&url, base, sl->d);
|
||
free_strlist (sl);
|
||
if (err)
|
||
{
|
||
/* fixme: cleanup argv. */
|
||
return err;
|
||
}
|
||
argv[argc++] = url;
|
||
}
|
||
argv[argc] = NULL;
|
||
|
||
*context = xtrycalloc (1, sizeof **context);
|
||
if (!*context)
|
||
return gpg_error_from_errno (errno);
|
||
|
||
err = ldap_wrapper (ctrl, &(*context)->reader, argv);
|
||
|
||
if (err)
|
||
{
|
||
xfree (*context);
|
||
*context = NULL;
|
||
}
|
||
|
||
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;
|
||
|
||
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;
|
||
int n;
|
||
int okay = 0;
|
||
/* int is_cms = 0; */
|
||
|
||
*value = NULL;
|
||
*valuelen = 0;
|
||
|
||
err = 0;
|
||
while (!err)
|
||
{
|
||
err = read_buffer (context->reader, hdr, 5);
|
||
if (err)
|
||
break;
|
||
n = (hdr[1] << 24)|(hdr[2]<<16)|(hdr[3]<<8)|hdr[4];
|
||
if (*hdr == 'V' && okay)
|
||
{
|
||
#if 0 /* That code is not yet ready. */
|
||
|
||
if (is_cms)
|
||
{
|
||
/* The certificate needs to be parsed from CMS data. */
|
||
ksba_cms_t cms;
|
||
ksba_stop_reason_t stopreason;
|
||
int i;
|
||
|
||
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;
|
||
}
|
||
|
||
do
|
||
{
|
||
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");
|
||
}
|
||
while (stopreason != KSBA_SR_READY);
|
||
|
||
for (i=0; (cert=ksba_cms_get_cert (cms, i)); i++)
|
||
{
|
||
check_and_store (ctrl, stats, cert, 0);
|
||
ksba_cert_release (cert);
|
||
cert = NULL;
|
||
}
|
||
if (!i)
|
||
log_error ("no certificate found\n");
|
||
else
|
||
any = 1;
|
||
}
|
||
else
|
||
#endif
|
||
{
|
||
*value = xtrymalloc (n);
|
||
if (!*value)
|
||
return gpg_error_from_errno (errno);
|
||
*valuelen = n;
|
||
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;
|
||
}
|
||
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.)*/
|
||
/* fixme: is_cms = 0; */
|
||
if ( (pend = strchr (p, ';')) )
|
||
*pend = 0; /* Strip off the extension. */
|
||
if (!ascii_strcasecmp (p, USERCERTIFICATE))
|
||
{
|
||
if (DBG_LOOKUP)
|
||
log_debug ("fetch_next_cert_ldap: got attribute '%s'\n",
|
||
USERCERTIFICATE);
|
||
okay = 1;
|
||
}
|
||
else if (!ascii_strcasecmp (p, CACERTIFICATE))
|
||
{
|
||
if (DBG_LOOKUP)
|
||
log_debug ("fetch_next_cert_ldap: got attribute '%s'\n",
|
||
CACERTIFICATE);
|
||
okay = 1;
|
||
}
|
||
else if (!ascii_strcasecmp (p, X509CACERT))
|
||
{
|
||
if (DBG_LOOKUP)
|
||
log_debug ("fetch_next_cert_ldap: got attribute '%s'\n",
|
||
CACERTIFICATE);
|
||
okay = 1;
|
||
}
|
||
/* else if (!ascii_strcasecmp (p, USERSMIMECERTIFICATE)) */
|
||
/* { */
|
||
/* if (DBG_LOOKUP) */
|
||
/* log_debug ("fetch_next_cert_ldap: got attribute '%s'\n", */
|
||
/* USERSMIMECERTIFICATE); */
|
||
/* okay = 1; */
|
||
/* is_cms = 1; */
|
||
/* } */
|
||
else
|
||
{
|
||
if (DBG_LOOKUP)
|
||
log_debug ("fetch_next_cert_ldap: got attribute '%s'"
|
||
" - 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);
|
||
}
|
||
}
|