Bump to 2.4.3
[platform/upstream/gpg2.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, 2021 g10 Code GmbH
4  *
5  * This file is part of GnuPG.
6  *
7  * GnuPG 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 3 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, see <https://www.gnu.org/licenses/>.
19  * SPDX-License-Identifier: GPL-3.0-or-later
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 "ldap-url.h"
40 #include "../common/host2net.h"
41
42
43 #define UNENCODED_URL_CHARS "abcdefghijklmnopqrstuvwxyz"   \
44                             "ABCDEFGHIJKLMNOPQRSTUVWXYZ"   \
45                             "01234567890"                  \
46                             "$-_.+!*'(),"
47 #define USERCERTIFICATE "userCertificate"
48 #define CACERTIFICATE   "caCertificate"
49 #define X509CACERT      "x509caCert"
50 #define USERSMIMECERTIFICATE "userSMIMECertificate"
51
52
53 /* Definition for the context of the cert fetch functions. */
54 struct cert_fetch_context_s
55 {
56   ksba_reader_t reader;  /* The reader used (shallow copy). */
57   unsigned char *tmpbuf; /* Helper buffer.  */
58   size_t tmpbufsize;     /* Allocated size of tmpbuf.  */
59   int truncated;         /* Flag to indicate a truncated output.  */
60 };
61
62
63
64 \f
65 /* Add HOST and PORT to our list of LDAP servers.  Fixme: We should
66    better use an extra list of servers. */
67 static void
68 add_server_to_servers (const char *host, int port)
69 {
70   ldap_server_t server;
71   ldap_server_t last = NULL;
72   const char *s;
73
74   if (!port)
75     port = 389;
76
77   for (server=opt.ldapservers; server; server = server->next)
78     {
79       if (!strcmp (server->host, host) && server->port == port)
80           return; /* already in list... */
81       last = server;
82     }
83
84   /* We assume that the host names are all supplied by our
85      configuration files and thus are sane.  To keep this assumption
86      we must reject all invalid host names. */
87   for (s=host; *s; s++)
88     if (!strchr ("abcdefghijklmnopqrstuvwxyz"
89                  "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
90                  "01234567890.-", *s))
91       {
92         log_error (_("invalid char 0x%02x in host name - not added\n"), *s);
93         return;
94       }
95
96   log_info (_("adding '%s:%d' to the ldap server list\n"), host, port);
97   server = xtrycalloc (1, sizeof *s);
98   if (!server)
99     log_error (_("malloc failed: %s\n"), strerror (errno));
100   else
101     {
102       server->host = xstrdup (host);
103       server->port = port;
104       if (last)
105         last->next = server;
106       else
107         opt.ldapservers = server;
108     }
109 }
110
111
112
113
114 /* Perform an LDAP query.  Returns an gpg error code or 0 on success.
115    The function returns a new reader object at READER. */
116 static gpg_error_t
117 run_ldap_wrapper (ctrl_t ctrl,
118                   int ignore_timeout,
119                   int multi_mode,
120                   int tls_mode,
121                   int ntds,
122                   int areconly,
123                   const char *proxy,
124                   const char *host, int port,
125                   const char *user, const char *pass,
126                   const char *base, const char *filter, const char *attr,
127                   ksba_reader_t *reader)
128 {
129   const char *argv[51];
130   int argc;
131   char portbuf[30], timeoutbuf[30];
132
133
134   *reader = NULL;
135
136   argc = 0;
137   if (pass && *pass)  /* Note, that the password must be the first item.  */
138     {
139       argv[argc++] = "--pass";
140       argv[argc++] = pass;
141     }
142
143   if (DBG_LOOKUP)
144     argv[argc++] = "-vv";
145   else if (DBG_EXTPROG)
146     argv[argc++] = "-v";
147
148   argv[argc++] = "--log-with-pid";
149   if (multi_mode)
150     argv[argc++] = "--multi";
151
152   if (tls_mode == 1)
153     argv[argc++] = "--starttls";
154   else if (tls_mode)
155     argv[argc++] = "--ldaptls";
156
157   if (ntds)
158     argv[argc++] = "--ntds";
159
160   if (areconly)
161     argv[argc++] = "--areconly";
162
163   if (opt.ldaptimeout)
164     {
165       snprintf (timeoutbuf, sizeof timeoutbuf, "%u", opt.ldaptimeout);
166       argv[argc++] = "--timeout";
167       argv[argc++] = timeoutbuf;
168       if (ignore_timeout)
169         argv[argc++] = "--only-search-timeout";
170     }
171   if (proxy)
172     {
173       argv[argc++] = "--proxy";
174       argv[argc++] = proxy;
175     }
176   if (host && *host)
177     {
178       argv[argc++] = "--host";
179       argv[argc++] = host;
180     }
181   if (port)
182     {
183       sprintf (portbuf, "%d", port);
184       argv[argc++] = "--port";
185       argv[argc++] = portbuf;
186     }
187   if (user && *user)
188     {
189       argv[argc++] = "--user";
190       argv[argc++] = user;
191     }
192   if (base && *base)
193     {
194       argv[argc++] = "--base";
195       argv[argc++] = base;
196     }
197   if (attr)
198     {
199       argv[argc++] = "--attr";
200       argv[argc++] = attr;
201     }
202
203   if (filter)
204     argv[argc++] = filter;
205   argv[argc] = NULL;
206
207   return ldap_wrapper (ctrl, reader, argv);
208 }
209
210
211
212
213 /* Perform a LDAP query using a given URL. On success a new ksba
214    reader is returned.  If HOST or PORT are not 0, they are used to
215    override the values from the URL. */
216 gpg_error_t
217 url_fetch_ldap (ctrl_t ctrl, const char *url, ksba_reader_t *reader)
218 {
219   gpg_error_t err;
220   LDAPURLDesc *ludp = NULL;
221   int tls_mode;
222
223   if (!ldap_is_ldap_url (url))
224     {
225       log_error (_("'%s' is not an LDAP URL\n"), url);
226       return gpg_error (GPG_ERR_INV_URI);
227     }
228
229   if (ldap_url_parse (url, &ludp))
230     {
231       log_error (_("'%s' is an invalid LDAP URL\n"), url);
232       return gpg_error (GPG_ERR_INV_URI);
233     }
234
235   if (ludp->lud_filter && ludp->lud_filter[0] != '(')
236     {
237       if (!strcmp (ludp->lud_filter, "objectClass=cRLDistributionPoint"))
238         {
239           /* Hack for broken DPs in DGN certs.  */
240           log_info ("fixing broken LDAP URL\n");
241           free (ludp->lud_filter);
242           ludp->lud_filter
243             = strdup ("(objectClass=cRLDistributionPoint)");
244           if (!ludp->lud_filter)
245             {
246               err = gpg_error_from_syserror ();
247               goto leave;
248             }
249         }
250       else
251         {
252           log_error (_("'%s' is an invalid LDAP URL\n"), url);
253           err = gpg_error (GPG_ERR_BAD_URI);
254           goto leave;
255         }
256     }
257
258   if (ludp->lud_scheme && !strcmp (ludp->lud_scheme, "ldaps"))
259     tls_mode = 2; /* LDAP-over-TLS here becuase we get it from certs. */
260   else
261     tls_mode = 0;
262
263   err = run_ldap_wrapper (ctrl,
264                           1, /* Ignore explicit timeout because CRLs
265                                 might be very large. */
266                           0, /* No Multi-mode.  */
267                           tls_mode,
268                           0, /* No AD authentication.  */
269                           0, /* No areconly.  */
270                           opt.ldap_proxy,
271                           ludp->lud_host, ludp->lud_port,
272                           NULL, NULL,  /* user, password */
273                           ludp->lud_dn,    /* Base DN */
274                           ludp->lud_filter,
275                           ludp->lud_attrs? ludp->lud_attrs[0] : NULL,
276                           reader);
277
278   /* FIXME: This option might be used for DoS attacks.  Because it
279      will enlarge the list of servers to consult without a limit and
280      all LDAP queries w/o a host are will then try each host in
281      turn. */
282   if (!err && opt.add_new_ldapservers && !opt.ldap_proxy)
283     {
284       if (ludp->lud_host)
285         add_server_to_servers (ludp->lud_host, ludp->lud_port);
286     }
287
288   /* If the lookup failed and we are not only using the proxy, we try
289      again using our default list of servers.  */
290   if (err && !(opt.ldap_proxy && opt.only_ldap_proxy))
291     {
292       struct ldapserver_iter iter;
293
294       if (DBG_LOOKUP)
295         log_debug ("no hostname in URL or query failed; "
296                    "trying all default hostnames\n");
297
298       for (ldapserver_iter_begin (&iter, ctrl);
299            err && ! ldapserver_iter_end_p (&iter);
300            ldapserver_iter_next (&iter))
301         {
302           ldap_server_t server = iter.server;
303
304           if (server->starttls)
305             tls_mode = 1;
306           else if (server->ldap_over_tls)
307             tls_mode = 2;
308           else
309             tls_mode = 0;
310
311           err = run_ldap_wrapper (ctrl,
312                                   0,
313                                   0, /* No Multi-mode */
314                                   tls_mode,
315                                   server->ntds,
316                                   server->areconly,
317                                   NULL,
318                                   server->host, server->port,
319                                   server->user, server->pass,
320                                   server->base,
321                                   ludp->lud_filter,
322                                   ludp->lud_attrs? ludp->lud_attrs[0] : NULL,
323                                   reader);
324           if (!err)
325             break;
326         }
327     }
328
329  leave:
330   ldap_free_urldesc (ludp);
331   return err;
332 }
333
334
335
336 /* Perform an LDAP query on all configured servers.  On error the
337    error code of the last try is returned.  */
338 gpg_error_t
339 attr_fetch_ldap (ctrl_t ctrl,
340                  const char *dn, const char *attr, ksba_reader_t *reader)
341 {
342   gpg_error_t err = gpg_error (GPG_ERR_CONFIGURATION);
343   struct ldapserver_iter iter;
344
345   *reader = NULL;
346
347   /* FIXME; we might want to look at the Base DN to try matching
348      servers first. */
349   for (ldapserver_iter_begin (&iter, ctrl); ! ldapserver_iter_end_p (&iter);
350        ldapserver_iter_next (&iter))
351     {
352       ldap_server_t server = iter.server;
353       int tls_mode;
354
355       if (server->starttls)
356         tls_mode = 1;
357       else if (server->ldap_over_tls)
358         tls_mode = 2;
359       else
360         tls_mode = 0;
361
362       err = run_ldap_wrapper (ctrl,
363                               0,
364                               0,
365                               tls_mode,
366                               server->ntds,
367                               server->areconly,
368                               opt.ldap_proxy,
369                               server->host, server->port,
370                               server->user, server->pass,
371                               dn,
372                               "(objectClass=*)",
373                               attr,
374                               reader);
375       if (!err)
376         break; /* Probably found a result. Ready. */
377     }
378   return err;
379 }
380
381
382 \f
383 /* Return true if VALUE needs escaping.  */
384 static int
385 rfc2254_need_escape (const char *value)
386 {
387   /* NUL needs to be escaped as well but we can represent that in
388    * VALUE, so no need for it.  */
389   return !!strpbrk (value, "*()\\");
390 }
391
392 /* Escape VALUE using RFC-2254 rules.  Returns NULL on error. */
393 static char *
394 rfc2254_escape (const char *value)
395 {
396   const char *s;
397   char *buffer, *p;
398   size_t length = 0;
399
400   for (s=value; *s; s++)
401     switch (*s)
402       {
403       case '*':
404       case '(':
405       case ')':
406       case '\\': length += 3; break;
407       default:   length++; break;
408       }
409
410   buffer = xtrymalloc (length+1);
411   if (!buffer)
412     return NULL;
413   p = buffer;
414   for (s=value; *s; s++)
415     switch (*s)
416       {
417       case '*':  p = stpcpy (p, "\\2a"); break;
418       case '(':  p = stpcpy (p, "\\28"); break;
419       case ')':  p = stpcpy (p, "\\29"); break;
420       case '\\': p = stpcpy (p, "\\5c"); break;
421       default:   *p++ = *s; break;
422       }
423   *p = 0;
424   return buffer;
425 }
426
427
428 /* Return true if VALUE needs escaping.  */
429 static int
430 extfilt_need_escape (const char *value)
431 {
432   /* NUL needs to be escaped as well but we can represent that in
433    * VALUE, so no need for it.  */
434   return !!strchr (value, '&');
435 }
436
437 /* Escape VALUE using our extended filter rules from dirmngr_ldap.c.
438  * Returns NULL on error. */
439 static char *
440 extfilt_escape (const char *value)
441 {
442   const char *s;
443   char *buffer, *p;
444   size_t length = 0;
445
446   for (s=value; *s; s++)
447     {
448       length++;
449       if (*s == '&')
450         length++;
451     }
452
453   buffer = xtrymalloc (length+1);
454   if (!buffer)
455     return NULL;
456   p = buffer;
457   for (s=value; *s; s++)
458     {
459       *p++ = *s;
460       if (*s == '&')
461         *p++ = '&';
462     }
463   *p = 0;
464   return buffer;
465 }
466
467
468 /* Parse PATTERN and return a new filter expression for an LDAP query.
469  * The extended filter syntax as known by dirmngr_ldap.c is used.
470  * Caller must release the returned value.  R_RESULT is set to NULL on
471  * error.
472  *
473  * Supported patterns:
474  *
475  *  | Ok  | gpg style user id type                               |
476  *  |-----+------------------------------------------------------|
477  *  | no  | KeyID                                                |
478  *  | no  | Fingerprint                                          |
479  *  | no  | OpenPGP userid                                       |
480  *  | yes | Email address  Indicated by a left angle bracket.    |
481  *  | no  | Exact word match in user id or subj. name            |
482  *  | yes | Subj. DN  indicated by a leading slash               |
483  *  | no  | Issuer DN                                            |
484  *  | no  | Serial number + subj. DN                             |
485  *  | yes | Substring match indicated by a leading '*; (default) |
486  */
487 static gpg_error_t
488 make_one_filter (const char *pattern, char **r_result)
489 {
490   gpg_error_t err = 0;
491   char *pattern_buffer = NULL;
492   char *result = NULL;
493   size_t n;
494
495   *r_result = NULL;
496
497   switch (*pattern)
498     {
499     case '<':                   /* Email. */
500       {
501         pattern++;
502         if (rfc2254_need_escape (pattern)
503             && !(pattern = pattern_buffer = rfc2254_escape (pattern)))
504           {
505             err = gpg_error_from_syserror ();
506             goto leave;
507           }
508         result = strconcat ("(mail=", pattern, ")", NULL);
509         if (!result)
510           {
511             err = gpg_error_from_syserror ();
512             goto leave;
513           }
514         n = strlen (result);
515         if (result[n-2] == '>') /* Strip trailing '>' */
516           {
517             result[n-2] = ')';
518             result[n-1] = 0;
519           }
520         break;
521       }
522     case '/':                   /* Subject DN. */
523       pattern++;
524       if (*pattern)
525         {
526           /* We need just the BaseDN.  This assumes that the Subject
527            * is correcly stored in the DT.  This is however not always
528            * the case and the actual DN is different from the
529            * subject.  In this case we won't find anything.  */
530           if (extfilt_need_escape (pattern)
531               && !(pattern = pattern_buffer = extfilt_escape (pattern)))
532             {
533               err = gpg_error_from_syserror ();
534               goto leave;
535             }
536           result = strconcat ("^", pattern, "&base&", NULL);
537           if (!result)
538             {
539               err = gpg_error_from_syserror ();
540               goto leave;
541             }
542         }
543       break;
544     case '#':                   /* Issuer DN - Not yet working. */
545       pattern++;
546       if (*pattern == '/')  /* Just issuer DN. */
547         {
548           pattern++;
549           if (extfilt_need_escape (pattern)
550               && !(pattern = pattern_buffer = extfilt_escape (pattern)))
551             {
552               err = gpg_error_from_syserror ();
553               goto leave;
554             }
555           result = strconcat ("^", pattern, "&base&", NULL);
556           if (!result)
557             {
558               err = gpg_error_from_syserror ();
559               goto leave;
560             }
561         }
562       else  /* Serial number + issuer DN */
563         {
564
565         }
566       break;
567     case '*':
568       pattern++;
569       /* fall through */
570     default:                    /* Take as substring match. */
571       if (*pattern)
572         {
573           if (rfc2254_need_escape (pattern)
574               && !(pattern = pattern_buffer = rfc2254_escape (pattern)))
575             {
576               err = gpg_error_from_syserror ();
577               goto leave;
578             }
579           result = strconcat ("(|(sn=*", pattern,
580                               "*)(|(cn=*", pattern,
581                               "*)(mail=*", pattern,
582                               "*)))", NULL);
583           if (!result)
584             {
585               err = gpg_error_from_syserror ();
586               goto leave;
587             }
588         }
589       break;
590     }
591
592   if (!result)
593     err = gpg_error (GPG_ERR_INV_USER_ID);
594
595  leave:
596   xfree (pattern_buffer);
597   if (err)
598     xfree (result);
599   else
600     *r_result = result;
601   return err;
602 }
603
604
605
606 /* Prepare an LDAP query to return the cACertificate attribute for DN.
607  * All configured default servers are queried until one responds.
608  * This function returns an error code or 0 and stored a newly
609  * allocated contect object at CONTEXT on success. */
610 gpg_error_t
611 start_cacert_fetch_ldap (ctrl_t ctrl, cert_fetch_context_t *r_context,
612                          const char *dn)
613 {
614   gpg_error_t err;
615   struct ldapserver_iter iter;
616
617   *r_context = xtrycalloc (1, sizeof **r_context);
618   if (!*r_context)
619     return gpg_error_from_errno (errno);
620
621   /* FIXME; we might want to look at the Base DN to try matching
622      servers first. */
623   err = gpg_error (GPG_ERR_CONFIGURATION);
624
625   for (ldapserver_iter_begin (&iter, ctrl); ! ldapserver_iter_end_p (&iter);
626        ldapserver_iter_next (&iter))
627     {
628       ldap_server_t server = iter.server;
629
630       err = run_ldap_wrapper (ctrl,
631                               0,
632                               1,  /* --multi (record format) */
633                               0, /* No TLS */
634                               0, /* No AD authentication.  */
635                               server->areconly,
636                               opt.ldap_proxy,
637                               server->host, server->port,
638                               server->user, server->pass,
639                               dn, "objectClass=*", "cACertificate",
640                               &(*r_context)->reader);
641       if (!err)
642         break; /* Probably found a result. */
643     }
644
645   if (err)
646     {
647       xfree (*r_context);
648       *r_context = NULL;
649     }
650   return err;
651 }
652
653
654 /* Prepare an LDAP query to return certificates matching PATTERNS
655  * using the SERVER.  This function returns an error code or 0 and
656  * stores a newly allocated object at R_CONTEXT on success. */
657 gpg_error_t
658 start_cert_fetch_ldap (ctrl_t ctrl, cert_fetch_context_t *r_context,
659                        strlist_t patterns, const ldap_server_t server)
660 {
661   gpg_error_t err;
662   char *proxy = NULL;
663   char *host = NULL;
664   int port;
665   char *user = NULL;
666   char *pass = NULL;
667   char *base = NULL;
668   char *argv[50];
669   int argc = 0;
670   int argc_malloced = 0;
671   char portbuf[30], timeoutbuf[30];
672   int starttls, ldaptls, ntds;
673
674   *r_context = NULL;
675
676   if (opt.ldap_proxy && !(proxy = xtrystrdup (opt.ldap_proxy)))
677     {
678       err = gpg_error_from_syserror ();
679       goto leave;
680     }
681
682   if (server)
683     {
684       if (server->host && !(host = xtrystrdup (server->host)))
685         {
686           err = gpg_error_from_syserror ();
687           goto leave;
688         }
689       port = server->port;
690       if (server->user && !(user = xtrystrdup (server->user)))
691         {
692           err = gpg_error_from_syserror ();
693           goto leave;
694         }
695       if (server->pass && !(pass = xtrystrdup (server->pass)))
696         {
697           err = gpg_error_from_syserror ();
698           goto leave;
699         }
700       if (server->base && !(base = xtrystrdup (server->base)))
701         {
702           err = gpg_error_from_syserror ();
703           goto leave;
704         }
705
706       starttls = server->starttls;
707       ldaptls  =  server->ldap_over_tls;
708       ntds     = server->ntds;
709     }
710   else /* Use a default server. */
711     {
712       err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
713       goto leave;
714     }
715
716
717   if (pass && *pass) /* Note: Must be the first item. */
718     {
719       argv[argc++] = "--pass";
720       argv[argc++] = pass;
721     }
722
723   if (DBG_LOOKUP)
724     argv[argc++] = "-vv";
725   else if (DBG_EXTPROG)
726     argv[argc++] = "-v";
727
728   argv[argc++] = "--log-with-pid";
729   argv[argc++] = "--multi";
730
731   if (starttls)
732     argv[argc++] = "--starttls";
733   else if (ldaptls)
734     argv[argc++] = "--ldaptls";
735
736   if (ntds)
737     argv[argc++] = "--ntds";
738
739   if (opt.ldaptimeout)
740     {
741       snprintf (timeoutbuf, sizeof timeoutbuf, "%u", opt.ldaptimeout);
742       argv[argc++] = "--timeout";
743       argv[argc++] = timeoutbuf;
744     }
745   if (proxy && *proxy)
746     {
747       argv[argc++] = "--proxy";
748       argv[argc++] = proxy;
749     }
750   if (host && *host)
751     {
752       argv[argc++] = "--host";
753       argv[argc++] = host;
754     }
755   if (port)
756     {
757       snprintf (portbuf, sizeof portbuf, "%d", port);
758       argv[argc++] = "--port";
759       argv[argc++] = portbuf;
760     }
761   if (user && *user)
762     {
763       argv[argc++] = "--user";
764       argv[argc++] = user;
765     }
766   if (base && *base)
767     {
768       argv[argc++] = "--base";
769       argv[argc++] = base;
770     }
771
772
773   /* All entries in argv from this index on are malloc'ed.  */
774   argc_malloced = argc;
775
776   for (; patterns; patterns = patterns->next)
777     {
778       if (argc >= DIM (argv) - 1)
779         {
780           /* Too many patterns.  It does not make sense to allow an
781              arbitrary number of patters because the length of the
782              command line is limited anyway.  */
783           err = gpg_error (GPG_ERR_RESOURCE_LIMIT);
784           goto leave;
785         }
786       if (*patterns->d)
787         {
788           err = make_one_filter (patterns->d, &argv[argc]);
789           if (err)
790             goto leave;
791           argc++;
792         }
793     }
794   argv[argc] = NULL;
795
796   *r_context = xtrycalloc (1, sizeof **r_context);
797   if (!*r_context)
798     {
799       err = gpg_error_from_syserror ();
800       goto leave;
801     }
802
803   err = ldap_wrapper (ctrl, &(*r_context)->reader, (const char**)argv);
804   if (err)
805     {
806       xfree (*r_context);
807       *r_context = NULL;
808     }
809
810  leave:
811   for (; argc_malloced < argc; argc_malloced++)
812     xfree (argv[argc_malloced]);
813   xfree (proxy);
814   xfree (host);
815   xfree (base);
816   xfree (user);
817   xfree (pass);
818   return err;
819 }
820
821
822 /* Read a fixed amount of data from READER into BUFFER.  */
823 static gpg_error_t
824 read_buffer (ksba_reader_t reader, unsigned char *buffer, size_t count)
825 {
826   gpg_error_t err;
827   size_t nread;
828
829   while (count)
830     {
831       err = ksba_reader_read (reader, buffer, count, &nread);
832       if (err)
833         return err;
834       buffer += nread;
835       count -= nread;
836     }
837   return 0;
838 }
839
840
841 /* Fetch the next certificate. Return 0 on success, GPG_ERR_EOF if no
842    (more) certificates are available or any other error
843    code. GPG_ERR_TRUNCATED may be returned to indicate that the result
844    has been truncated. */
845 gpg_error_t
846 fetch_next_cert_ldap (cert_fetch_context_t context,
847                       unsigned char **value, size_t *valuelen)
848 {
849   gpg_error_t err;
850   unsigned char hdr[5];
851   char *p, *pend;
852   unsigned long n;
853   int okay = 0;
854   /* int is_cms = 0; */
855
856   *value = NULL;
857   *valuelen = 0;
858
859   err = 0;
860   while (!err)
861     {
862       err = read_buffer (context->reader, hdr, 5);
863       if (err)
864         break;
865       n = buf32_to_ulong (hdr+1);
866       if (*hdr == 'V' && okay)
867         {
868 #if 0  /* That code to extra a cert from a CMS object is not yet ready.  */
869           if (is_cms)
870             {
871               /* The certificate needs to be parsed from CMS data. */
872               ksba_cms_t cms;
873               ksba_stop_reason_t stopreason;
874               int i;
875
876               err = ksba_cms_new (&cms);
877               if (err)
878                 goto leave;
879               err = ksba_cms_set_reader_writer (cms, context->reader, NULL);
880               if (err)
881                 {
882                   log_error ("ksba_cms_set_reader_writer failed: %s\n",
883                              gpg_strerror (err));
884                   goto leave;
885                 }
886
887               do
888                 {
889                   err = ksba_cms_parse (cms, &stopreason);
890                   if (err)
891                     {
892                       log_error ("ksba_cms_parse failed: %s\n",
893                                  gpg_strerror (err));
894                       goto leave;
895                     }
896
897                   if (stopreason == KSBA_SR_BEGIN_DATA)
898                     log_error ("userSMIMECertificate is not "
899                                "a certs-only message\n");
900                 }
901               while (stopreason != KSBA_SR_READY);
902
903               for (i=0; (cert=ksba_cms_get_cert (cms, i)); i++)
904                 {
905                   check_and_store (ctrl, stats, cert, 0);
906                   ksba_cert_release (cert);
907                   cert = NULL;
908                 }
909               if (!i)
910                 log_error ("no certificate found\n");
911               else
912                 any = 1;
913             }
914           else
915 #endif /* End unfinished code to extract from a CMS object.  */
916             {
917               *value = xtrymalloc (n);
918               if (!*value)
919                 return gpg_error_from_errno (errno);
920               *valuelen = n;
921               err = read_buffer (context->reader, *value, n);
922               break; /* Ready or error.  */
923             }
924         }
925       else if (!n && *hdr == 'A')
926         okay = 0;
927       else if (n)
928         {
929           if (n > context->tmpbufsize)
930             {
931               xfree (context->tmpbuf);
932               context->tmpbufsize = 0;
933               context->tmpbuf = xtrymalloc (n+1);
934               if (!context->tmpbuf)
935                 return gpg_error_from_errno (errno);
936               context->tmpbufsize = n;
937             }
938           err = read_buffer (context->reader, context->tmpbuf, n);
939           if (err)
940             break;
941           if (*hdr == 'A')
942             {
943               p = context->tmpbuf;
944               p[n] = 0; /*(we allocated one extra byte for this.)*/
945               /* fixme: is_cms = 0; */
946               if ( (pend = strchr (p, ';')) )
947                 *pend = 0; /* Strip off the extension. */
948               if (!ascii_strcasecmp (p, USERCERTIFICATE))
949                 {
950                   if (DBG_LOOKUP)
951                     log_debug ("fetch_next_cert_ldap: got attribute '%s'\n",
952                                USERCERTIFICATE);
953                   okay = 1;
954                 }
955               else if (!ascii_strcasecmp (p, CACERTIFICATE))
956                 {
957                   if (DBG_LOOKUP)
958                     log_debug ("fetch_next_cert_ldap: got attribute '%s'\n",
959                                CACERTIFICATE);
960                   okay = 1;
961                 }
962               else if (!ascii_strcasecmp (p, X509CACERT))
963                 {
964                   if (DBG_LOOKUP)
965                     log_debug ("fetch_next_cert_ldap: got attribute '%s'\n",
966                                CACERTIFICATE);
967                   okay = 1;
968                 }
969 /*               else if (!ascii_strcasecmp (p, USERSMIMECERTIFICATE)) */
970 /*                 { */
971 /*                   if (DBG_LOOKUP) */
972 /*                     log_debug ("fetch_next_cert_ldap: got attribute '%s'\n", */
973 /*                                USERSMIMECERTIFICATE); */
974 /*                   okay = 1; */
975 /*                   is_cms = 1; */
976 /*                 } */
977               else
978                 {
979                   if (DBG_LOOKUP)
980                     log_debug ("fetch_next_cert_ldap: got attribute '%s'"
981                                " -  ignored\n", p);
982                   okay = 0;
983                 }
984             }
985           else if (*hdr == 'E')
986             {
987               p = context->tmpbuf;
988               p[n] = 0; /*(we allocated one extra byte for this.)*/
989               if (!strcmp (p, "truncated"))
990                 {
991                   context->truncated = 1;
992                   log_info (_("ldap_search hit the size limit of"
993                               " the server\n"));
994                 }
995             }
996         }
997     }
998
999   if (err)
1000     {
1001       xfree (*value);
1002       *value = NULL;
1003       *valuelen = 0;
1004       if (gpg_err_code (err) == GPG_ERR_EOF && context->truncated)
1005         {
1006           context->truncated = 0; /* So that the next call would return EOF. */
1007           err = gpg_error (GPG_ERR_TRUNCATED);
1008         }
1009     }
1010
1011   return err;
1012 }
1013
1014
1015 void
1016 end_cert_fetch_ldap (cert_fetch_context_t context)
1017 {
1018   if (context)
1019     {
1020       ksba_reader_t reader = context->reader;
1021
1022       xfree (context->tmpbuf);
1023       xfree (context);
1024       ldap_wrapper_release_context (reader);
1025       ksba_reader_release (reader);
1026     }
1027 }