doc: Fix distchek for generated eps file
[gnupg.git] / dirmngr / ldap.c
1 /* ldap.c - LDAP access
2  * Copyright (C) 2002 Klarälvdalens Datakonsult AB
3  * Copyright (C) 2003, 2004, 2005, 2007, 2008, 2010 g10 Code GmbH
4  *
5  * This file is part of DirMngr.
6  *
7  * DirMngr is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * DirMngr is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
20  */
21
22 #include <config.h>
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <errno.h>
28 #include <unistd.h>
29 #include <fcntl.h>
30 #include <time.h>
31 #include <npth.h>
32
33 #include "dirmngr.h"
34 #include "../common/exechelp.h"
35 #include "crlfetch.h"
36 #include "ldapserver.h"
37 #include "misc.h"
38 #include "ldap-wrapper.h"
39 #include "../common/host2net.h"
40
41
42 #define UNENCODED_URL_CHARS "abcdefghijklmnopqrstuvwxyz"   \
43                             "ABCDEFGHIJKLMNOPQRSTUVWXYZ"   \
44                             "01234567890"                  \
45                             "$-_.+!*'(),"
46 #define USERCERTIFICATE "userCertificate"
47 #define CACERTIFICATE   "caCertificate"
48 #define X509CACERT      "x509caCert"
49 #define USERSMIMECERTIFICATE "userSMIMECertificate"
50
51
52 /* Definition for the context of the cert fetch functions. */
53 struct cert_fetch_context_s
54 {
55   ksba_reader_t reader;  /* The reader used (shallow copy). */
56   unsigned char *tmpbuf; /* Helper buffer.  */
57   size_t tmpbufsize;     /* Allocated size of tmpbuf.  */
58   int truncated;         /* Flag to indicate a truncated output.  */
59 };
60
61
62
63 \f
64 /* Add HOST and PORT to our list of LDAP servers.  Fixme: We should
65    better use an extra list of servers. */
66 static void
67 add_server_to_servers (const char *host, int port)
68 {
69   ldap_server_t server;
70   ldap_server_t last = NULL;
71   const char *s;
72
73   if (!port)
74     port = 389;
75
76   for (server=opt.ldapservers; server; server = server->next)
77     {
78       if (!strcmp (server->host, host) && server->port == port)
79           return; /* already in list... */
80       last = server;
81     }
82
83   /* We assume that the host names are all supplied by our
84      configuration files and thus are sane.  To keep this assumption
85      we must reject all invalid host names. */
86   for (s=host; *s; s++)
87     if (!strchr ("abcdefghijklmnopqrstuvwxyz"
88                  "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
89                  "01234567890.-", *s))
90       {
91         log_error (_("invalid char 0x%02x in host name - not added\n"), *s);
92         return;
93       }
94
95   log_info (_("adding '%s:%d' to the ldap server list\n"), host, port);
96   server = xtrycalloc (1, sizeof *s);
97   if (!server)
98     log_error (_("malloc failed: %s\n"), strerror (errno));
99   else
100     {
101       server->host = xstrdup (host);
102       server->port = port;
103       if (last)
104         last->next = server;
105       else
106         opt.ldapservers = server;
107     }
108 }
109
110
111
112
113 /* Perform an LDAP query.  Returns an gpg error code or 0 on success.
114    The function returns a new reader object at READER. */
115 static gpg_error_t
116 run_ldap_wrapper (ctrl_t ctrl,
117                   int ignore_timeout,
118                   int multi_mode,
119                   const char *proxy,
120                   const char *host, int port,
121                   const char *user, const char *pass,
122                   const char *dn, const char *filter, const char *attr,
123                   const char *url,
124                   ksba_reader_t *reader)
125 {
126   const char *argv[40];
127   int argc;
128   char portbuf[30], timeoutbuf[30];
129
130
131   *reader = NULL;
132
133   argc = 0;
134   if (pass)  /* Note, that the password must be the first item.  */
135     {
136       argv[argc++] = "--pass";
137       argv[argc++] = pass;
138     }
139
140   if (DBG_LOOKUP)
141     argv[argc++] = "-vv";
142   else if (DBG_EXTPROG)
143     argv[argc++] = "-v";
144
145   argv[argc++] = "--log-with-pid";
146   if (multi_mode)
147     argv[argc++] = "--multi";
148   if (opt.ldaptimeout)
149     {
150       sprintf (timeoutbuf, "%u", opt.ldaptimeout);
151       argv[argc++] = "--timeout";
152       argv[argc++] = timeoutbuf;
153       if (ignore_timeout)
154         argv[argc++] = "--only-search-timeout";
155     }
156   if (proxy)
157     {
158       argv[argc++] = "--proxy";
159       argv[argc++] = proxy;
160     }
161   if (host)
162     {
163       argv[argc++] = "--host";
164       argv[argc++] = host;
165     }
166   if (port)
167     {
168       sprintf (portbuf, "%d", port);
169       argv[argc++] = "--port";
170       argv[argc++] = portbuf;
171     }
172   if (user)
173     {
174       argv[argc++] = "--user";
175       argv[argc++] = user;
176     }
177   if (dn)
178     {
179       argv[argc++] = "--dn";
180       argv[argc++] = dn;
181     }
182   if (filter)
183     {
184       argv[argc++] = "--filter";
185       argv[argc++] = filter;
186     }
187   if (attr)
188     {
189       argv[argc++] = "--attr";
190       argv[argc++] = attr;
191     }
192   argv[argc++] = url? url : "ldap://";
193   argv[argc] = NULL;
194
195   return ldap_wrapper (ctrl, reader, argv);
196 }
197
198
199
200
201 /* Perform a LDAP query using a given URL. On success a new ksba
202    reader is returned.  If HOST or PORT are not 0, they are used to
203    override the values from the URL. */
204 gpg_error_t
205 url_fetch_ldap (ctrl_t ctrl, const char *url, const char *host, int port,
206                 ksba_reader_t *reader)
207 {
208   gpg_error_t err;
209
210   err = run_ldap_wrapper (ctrl,
211                           1, /* Ignore explicit timeout because CRLs
212                                 might be very large. */
213                           0,
214                           opt.ldap_proxy,
215                           host, port,
216                           NULL, NULL,
217                           NULL, NULL, NULL, url,
218                           reader);
219
220   /* FIXME: This option might be used for DoS attacks.  Because it
221      will enlarge the list of servers to consult without a limit and
222      all LDAP queries w/o a host are will then try each host in
223      turn. */
224   if (!err && opt.add_new_ldapservers && !opt.ldap_proxy)
225     {
226       if (host)
227         add_server_to_servers (host, port);
228       else if (url)
229         {
230           char *tmp = host_and_port_from_url (url, &port);
231           if (tmp)
232             {
233               add_server_to_servers (tmp, port);
234               xfree (tmp);
235             }
236         }
237     }
238
239   /* If the lookup failed and we are not only using the proxy, we try
240      again using our default list of servers.  */
241   if (err && !(opt.ldap_proxy && opt.only_ldap_proxy))
242     {
243       struct ldapserver_iter iter;
244
245       if (DBG_LOOKUP)
246         log_debug ("no hostname in URL or query failed; "
247                    "trying all default hostnames\n");
248
249       for (ldapserver_iter_begin (&iter, ctrl);
250            err && ! ldapserver_iter_end_p (&iter);
251            ldapserver_iter_next (&iter))
252         {
253           ldap_server_t server = iter.server;
254
255           err = run_ldap_wrapper (ctrl,
256                                   0,
257                                   0,
258                                   NULL,
259                                   server->host, server->port,
260                                   NULL, NULL,
261                                   NULL, NULL, NULL, url,
262                                   reader);
263           if (!err)
264             break;
265         }
266     }
267
268   return err;
269 }
270
271
272
273 /* Perform an LDAP query on all configured servers.  On error the
274    error code of the last try is returned.  */
275 gpg_error_t
276 attr_fetch_ldap (ctrl_t ctrl,
277                  const char *dn, const char *attr, ksba_reader_t *reader)
278 {
279   gpg_error_t err = gpg_error (GPG_ERR_CONFIGURATION);
280   struct ldapserver_iter iter;
281
282   *reader = NULL;
283
284   /* FIXME; we might want to look at the Base SN to try matching
285      servers first. */
286   for (ldapserver_iter_begin (&iter, ctrl); ! ldapserver_iter_end_p (&iter);
287        ldapserver_iter_next (&iter))
288     {
289       ldap_server_t server = iter.server;
290
291       err = run_ldap_wrapper (ctrl,
292                               0,
293                               0,
294                               opt.ldap_proxy,
295                               server->host, server->port,
296                               server->user, server->pass,
297                               dn, "objectClass=*", attr, NULL,
298                               reader);
299       if (!err)
300         break; /* Probably found a result. Ready. */
301     }
302   return err;
303 }
304
305 \f
306 /* Parse PATTERN and return a new strlist to be used for the actual
307    LDAP query.  Bit 0 of the flags field is set if that pattern is
308    actually a base specification.  Caller must release the returned
309    strlist.  NULL is returned on error.
310
311  * Possible patterns:
312  *
313  *   KeyID
314  *   Fingerprint
315  *   OpenPGP userid
316  * x Email address  Indicated by a left angle bracket.
317  *   Exact word match in user id or subj. name
318  * x Subj. DN  indicated bu a leading slash
319  *   Issuer DN
320  *   Serial number + subj. DN
321  * x Substring match indicated by a leading '*; is also the default.
322  */
323
324 strlist_t
325 parse_one_pattern (const char *pattern)
326 {
327   strlist_t result = NULL;
328   char *p;
329
330   switch (*pattern)
331     {
332     case '<':                   /* Email. */
333       {
334         pattern++;
335         result = xmalloc (sizeof *result + 5 + strlen (pattern));
336         result->next = NULL;
337         result->flags = 0;
338         p = stpcpy (stpcpy (result->d, "mail="), pattern);
339         if (p[-1] == '>')
340           *--p = 0;
341         if (!*result->d) /* Error. */
342           {
343             xfree (result);
344             result = NULL;
345           }
346         break;
347       }
348     case '/':                   /* Subject DN. */
349       pattern++;
350       if (*pattern)
351         {
352           result = xmalloc (sizeof *result + strlen (pattern));
353           result->next = NULL;
354           result->flags = 1; /* Base spec. */
355           strcpy (result->d, pattern);
356         }
357       break;
358     case '#':                   /* Issuer DN. */
359       pattern++;
360       if (*pattern == '/')  /* Just issuer DN. */
361         {
362           pattern++;
363         }
364       else  /* Serial number + issuer DN */
365         {
366         }
367       break;
368     case '*':
369       pattern++;
370       /* fall through */
371     default:                    /* Take as substring match. */
372       {
373         const char format[] = "(|(sn=*%s*)(|(cn=*%s*)(mail=*%s*)))";
374
375         if (*pattern)
376           {
377             result = xmalloc (sizeof *result
378                               + strlen (format) + 3 * strlen (pattern));
379             result->next = NULL;
380             result->flags = 0;
381             sprintf (result->d, format, pattern, pattern, pattern);
382           }
383       }
384       break;
385     }
386
387   return result;
388 }
389
390 /* Take the string STRING and escape it according to the URL rules.
391    Return a newly allocated string. */
392 static char *
393 escape4url (const char *string)
394 {
395   const char *s;
396   char *buf, *p;
397   size_t n;
398
399   if (!string)
400     string = "";
401
402   for (s=string,n=0; *s; s++)
403     if (strchr (UNENCODED_URL_CHARS, *s))
404       n++;
405     else
406       n += 3;
407
408   buf = malloc (n+1);
409   if (!buf)
410     return NULL;
411
412   for (s=string,p=buf; *s; s++)
413     if (strchr (UNENCODED_URL_CHARS, *s))
414       *p++ = *s;
415     else
416       {
417         sprintf (p, "%%%02X", *(const unsigned char *)s);
418         p += 3;
419       }
420   *p = 0;
421
422   return buf;
423 }
424
425
426
427 /* Create a LDAP URL from DN and FILTER and return it in URL.  We don't
428    need the host and port because this will be specified using the
429    override options. */
430 static gpg_error_t
431 make_url (char **url, const char *dn, const char *filter)
432 {
433   gpg_error_t err;
434   char *u_dn, *u_filter;
435   char const attrs[] = (USERCERTIFICATE ","
436 /*                         USERSMIMECERTIFICATE "," */
437                         CACERTIFICATE ","
438                         X509CACERT );
439
440   *url = NULL;
441
442   u_dn = escape4url (dn);
443   if (!u_dn)
444       return gpg_error_from_errno (errno);
445
446   u_filter = escape4url (filter);
447   if (!u_filter)
448     {
449       err = gpg_error_from_errno (errno);
450       xfree (u_dn);
451       return err;
452     }
453
454   *url = strconcat ("ldap:///", u_dn, "?", attrs, "?sub?", u_filter, NULL);
455   if (!*url)
456     err = gpg_error_from_syserror ();
457   else
458     err = 0;
459
460   xfree (u_dn);
461   xfree (u_filter);
462   return err;
463 }
464
465
466 /* Prepare an LDAP query to return the attribute ATTR for the DN.  All
467    configured default servers are queried until one responds.  This
468    function returns an error code or 0 and a CONTEXT on success. */
469 gpg_error_t
470 start_default_fetch_ldap (ctrl_t ctrl, cert_fetch_context_t *context,
471                           const char *dn, const char *attr)
472 {
473   gpg_error_t err;
474   struct ldapserver_iter iter;
475
476   *context = xtrycalloc (1, sizeof **context);
477   if (!*context)
478     return gpg_error_from_errno (errno);
479
480   /* FIXME; we might want to look at the Base SN to try matching
481      servers first. */
482   err = gpg_error (GPG_ERR_CONFIGURATION);
483
484   for (ldapserver_iter_begin (&iter, ctrl); ! ldapserver_iter_end_p (&iter);
485        ldapserver_iter_next (&iter))
486     {
487       ldap_server_t server = iter.server;
488
489       err = run_ldap_wrapper (ctrl,
490                               0,
491                               1,
492                               opt.ldap_proxy,
493                               server->host, server->port,
494                               server->user, server->pass,
495                               dn, "objectClass=*", attr, NULL,
496                               &(*context)->reader);
497       if (!err)
498         break; /* Probably found a result. */
499     }
500
501   if (err)
502     {
503       xfree (*context);
504       *context = NULL;
505     }
506   return err;
507 }
508
509
510 /* Prepare an LDAP query to return certificates matching PATTERNS using
511    the SERVER.  This function returns an error code or 0 and a CONTEXT
512    on success. */
513 gpg_error_t
514 start_cert_fetch_ldap (ctrl_t ctrl, cert_fetch_context_t *context,
515                        strlist_t patterns, const ldap_server_t server)
516 {
517   gpg_error_t err;
518   char *proxy = NULL;
519   char *host = NULL;
520   int port;
521   char *user = NULL;
522   char *pass = NULL;
523   const char *base;
524   char *argv[50];
525   int argc = 0;
526   int argc_malloced = 0;
527   char portbuf[30], timeoutbuf[30];
528
529
530   *context = NULL;
531
532   if (opt.ldap_proxy && !(proxy = xtrystrdup (opt.ldap_proxy)))
533     {
534       err = gpg_error_from_syserror ();
535       goto leave;
536     }
537
538   if (server)
539     {
540       if (server->host && !(host = xtrystrdup (server->host)))
541         {
542           err = gpg_error_from_syserror ();
543           goto leave;
544         }
545       port = server->port;
546       if (server->user && !(user = xtrystrdup (server->user)))
547         {
548           err = gpg_error_from_syserror ();
549           goto leave;
550         }
551       if (server->pass && !(pass = xtrystrdup (server->pass)))
552         {
553           err = gpg_error_from_syserror ();
554           goto leave;
555         }
556       base = server->base;
557
558     }
559   else /* Use a default server. */
560     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
561
562
563   if (!base)
564     base = "";
565
566   if (pass) /* Note: Must be the first item. */
567     {
568       argv[argc++] = "--pass";
569       argv[argc++] = pass;
570     }
571
572   if (DBG_LOOKUP)
573     argv[argc++] = "-vv";
574   else if (DBG_EXTPROG)
575     argv[argc++] = "-v";
576
577   argv[argc++] = "--log-with-pid";
578   argv[argc++] = "--multi";
579   if (opt.ldaptimeout)
580     {
581       snprintf (timeoutbuf, sizeof timeoutbuf, "%u", opt.ldaptimeout);
582       argv[argc++] = "--timeout";
583       argv[argc++] = timeoutbuf;
584     }
585   if (opt.ldap_proxy)
586     {
587       argv[argc++] = "--proxy";
588       argv[argc++] = proxy;
589     }
590   if (host)
591     {
592       argv[argc++] = "--host";
593       argv[argc++] = host;
594     }
595   if (port)
596     {
597       snprintf (portbuf, sizeof portbuf, "%d", port);
598       argv[argc++] = "--port";
599       argv[argc++] = portbuf;
600     }
601   if (user)
602     {
603       argv[argc++] = "--user";
604       argv[argc++] = user;
605     }
606
607   /* All entries in argv from this index on are malloc'ed.  */
608   argc_malloced = argc;
609
610   for (; patterns; patterns = patterns->next)
611     {
612       strlist_t sl;
613       char *url;
614
615       if (argc >= DIM (argv) - 1)
616         {
617           /* Too many patterns.  It does not make sense to allow an
618              arbitrary number of patters because the length of the
619              command line is limited anyway.  */
620           /* fixme: cleanup. */
621           return gpg_error (GPG_ERR_RESOURCE_LIMIT);
622         }
623       sl = parse_one_pattern (patterns->d);
624       if (!sl)
625         {
626           log_error (_("start_cert_fetch: invalid pattern '%s'\n"),
627                      patterns->d);
628           err = gpg_error (GPG_ERR_INV_USER_ID);
629           goto leave;
630         }
631       if ((sl->flags & 1))
632         err = make_url (&url, sl->d, "objectClass=*");
633       else
634         err = make_url (&url, base, sl->d);
635       free_strlist (sl);
636       if (err)
637         goto leave;
638       argv[argc++] = url;
639     }
640   argv[argc] = NULL;
641
642   *context = xtrycalloc (1, sizeof **context);
643   if (!*context)
644     {
645       err = gpg_error_from_errno (errno);
646       goto leave;
647     }
648
649   err = ldap_wrapper (ctrl, &(*context)->reader, (const char**)argv);
650
651   if (err)
652     {
653       xfree (*context);
654       *context = NULL;
655     }
656
657  leave:
658   for (; argc_malloced < argc; argc_malloced++)
659     xfree (argv[argc_malloced]);
660   xfree (proxy);
661   xfree (host);
662   xfree (user);
663   xfree (pass);
664   return err;
665 }
666
667
668 /* Read a fixed amount of data from READER into BUFFER.  */
669 static gpg_error_t
670 read_buffer (ksba_reader_t reader, unsigned char *buffer, size_t count)
671 {
672   gpg_error_t err;
673   size_t nread;
674
675   while (count)
676     {
677       err = ksba_reader_read (reader, buffer, count, &nread);
678       if (err)
679         return err;
680       buffer += nread;
681       count -= nread;
682     }
683   return 0;
684 }
685
686
687 /* Fetch the next certificate. Return 0 on success, GPG_ERR_EOF if no
688    (more) certificates are available or any other error
689    code. GPG_ERR_TRUNCATED may be returned to indicate that the result
690    has been truncated. */
691 gpg_error_t
692 fetch_next_cert_ldap (cert_fetch_context_t context,
693                       unsigned char **value, size_t *valuelen)
694 {
695   gpg_error_t err;
696   unsigned char hdr[5];
697   char *p, *pend;
698   unsigned long n;
699   int okay = 0;
700   /* int is_cms = 0; */
701
702   *value = NULL;
703   *valuelen = 0;
704
705   err = 0;
706   while (!err)
707     {
708       err = read_buffer (context->reader, hdr, 5);
709       if (err)
710         break;
711       n = buf32_to_ulong (hdr+1);
712       if (*hdr == 'V' && okay)
713         {
714 #if 0  /* That code is not yet ready.  */
715
716           if (is_cms)
717             {
718               /* The certificate needs to be parsed from CMS data. */
719               ksba_cms_t cms;
720               ksba_stop_reason_t stopreason;
721               int i;
722
723               err = ksba_cms_new (&cms);
724               if (err)
725                 goto leave;
726               err = ksba_cms_set_reader_writer (cms, context->reader, NULL);
727               if (err)
728                 {
729                   log_error ("ksba_cms_set_reader_writer failed: %s\n",
730                              gpg_strerror (err));
731                   goto leave;
732                 }
733
734               do
735                 {
736                   err = ksba_cms_parse (cms, &stopreason);
737                   if (err)
738                     {
739                       log_error ("ksba_cms_parse failed: %s\n",
740                                  gpg_strerror (err));
741                       goto leave;
742                     }
743
744                   if (stopreason == KSBA_SR_BEGIN_DATA)
745                     log_error ("userSMIMECertificate is not "
746                                "a certs-only message\n");
747                 }
748               while (stopreason != KSBA_SR_READY);
749
750               for (i=0; (cert=ksba_cms_get_cert (cms, i)); i++)
751                 {
752                   check_and_store (ctrl, stats, cert, 0);
753                   ksba_cert_release (cert);
754                   cert = NULL;
755                 }
756               if (!i)
757                 log_error ("no certificate found\n");
758               else
759                 any = 1;
760             }
761           else
762 #endif
763             {
764               *value = xtrymalloc (n);
765               if (!*value)
766                 return gpg_error_from_errno (errno);
767               *valuelen = n;
768               err = read_buffer (context->reader, *value, n);
769               break; /* Ready or error.  */
770             }
771         }
772       else if (!n && *hdr == 'A')
773         okay = 0;
774       else if (n)
775         {
776           if (n > context->tmpbufsize)
777             {
778               xfree (context->tmpbuf);
779               context->tmpbufsize = 0;
780               context->tmpbuf = xtrymalloc (n+1);
781               if (!context->tmpbuf)
782                 return gpg_error_from_errno (errno);
783               context->tmpbufsize = n;
784             }
785           err = read_buffer (context->reader, context->tmpbuf, n);
786           if (err)
787             break;
788           if (*hdr == 'A')
789             {
790               p = context->tmpbuf;
791               p[n] = 0; /*(we allocated one extra byte for this.)*/
792               /* fixme: is_cms = 0; */
793               if ( (pend = strchr (p, ';')) )
794                 *pend = 0; /* Strip off the extension. */
795               if (!ascii_strcasecmp (p, USERCERTIFICATE))
796                 {
797                   if (DBG_LOOKUP)
798                     log_debug ("fetch_next_cert_ldap: got attribute '%s'\n",
799                                USERCERTIFICATE);
800                   okay = 1;
801                 }
802               else if (!ascii_strcasecmp (p, CACERTIFICATE))
803                 {
804                   if (DBG_LOOKUP)
805                     log_debug ("fetch_next_cert_ldap: got attribute '%s'\n",
806                                CACERTIFICATE);
807                   okay = 1;
808                 }
809               else if (!ascii_strcasecmp (p, X509CACERT))
810                 {
811                   if (DBG_LOOKUP)
812                     log_debug ("fetch_next_cert_ldap: got attribute '%s'\n",
813                                CACERTIFICATE);
814                   okay = 1;
815                 }
816 /*               else if (!ascii_strcasecmp (p, USERSMIMECERTIFICATE)) */
817 /*                 { */
818 /*                   if (DBG_LOOKUP) */
819 /*                     log_debug ("fetch_next_cert_ldap: got attribute '%s'\n", */
820 /*                                USERSMIMECERTIFICATE); */
821 /*                   okay = 1; */
822 /*                   is_cms = 1; */
823 /*                 } */
824               else
825                 {
826                   if (DBG_LOOKUP)
827                     log_debug ("fetch_next_cert_ldap: got attribute '%s'"
828                                " -  ignored\n", p);
829                   okay = 0;
830                 }
831             }
832           else if (*hdr == 'E')
833             {
834               p = context->tmpbuf;
835               p[n] = 0; /*(we allocated one extra byte for this.)*/
836               if (!strcmp (p, "truncated"))
837                 {
838                   context->truncated = 1;
839                   log_info (_("ldap_search hit the size limit of"
840                               " the server\n"));
841                 }
842             }
843         }
844     }
845
846   if (err)
847     {
848       xfree (*value);
849       *value = NULL;
850       *valuelen = 0;
851       if (gpg_err_code (err) == GPG_ERR_EOF && context->truncated)
852         {
853           context->truncated = 0; /* So that the next call would return EOF. */
854           err = gpg_error (GPG_ERR_TRUNCATED);
855         }
856     }
857
858   return err;
859 }
860
861
862 void
863 end_cert_fetch_ldap (cert_fetch_context_t context)
864 {
865   if (context)
866     {
867       ksba_reader_t reader = context->reader;
868
869       xfree (context->tmpbuf);
870       xfree (context);
871       ldap_wrapper_release_context (reader);
872       ksba_reader_release (reader);
873     }
874 }