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