dirmngr: Allow building without LDAP support.
[gnupg.git] / dirmngr / crlfetch.c
1 /* crlfetch.c - LDAP access
2  *      Copyright (C) 2002 Klarälvdalens Datakonsult AB
3  *      Copyright (C) 2003, 2004, 2005, 2006, 2007 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, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include <config.h>
22
23 #include <stdio.h>
24 #include <errno.h>
25 #include <npth.h>
26
27 #include "crlfetch.h"
28 #include "dirmngr.h"
29 #include "misc.h"
30 #include "http.h"
31
32 #if USE_LDAP
33 # include "ldap-wrapper.h"
34 #endif
35
36 /* For detecting armored CRLs received via HTTP (yes, such CRLS really
37    exits, e.g. http://grid.fzk.de/ca/gridka-crl.pem at least in June
38    2008) we need a context in the reader callback.  */
39 struct reader_cb_context_s
40 {
41   estream_t fp;             /* The stream used with the ksba reader.  */
42   int checked:1;            /* PEM/binary detection ahs been done.    */
43   int is_pem:1;             /* The file stream is PEM encoded.        */
44   struct b64state b64state; /* The state used for Base64 decoding.    */
45 };
46
47
48 /* We need to associate a reader object with the reader callback
49    context.  This table is used for it. */
50 struct file_reader_map_s
51 {
52   ksba_reader_t reader;
53   struct reader_cb_context_s *cb_ctx;
54 };
55 #define MAX_FILE_READER 50
56 static struct file_reader_map_s file_reader_map[MAX_FILE_READER];
57
58 /* Associate FP with READER.  If the table is full wait until another
59    thread has removed an entry.  */
60 static void
61 register_file_reader (ksba_reader_t reader, struct reader_cb_context_s *cb_ctx)
62 {
63   int i;
64
65   for (;;)
66     {
67       for (i=0; i < MAX_FILE_READER; i++)
68         if (!file_reader_map[i].reader)
69           {
70             file_reader_map[i].reader = reader;
71             file_reader_map[i].cb_ctx = cb_ctx;
72             return;
73           }
74       log_info (_("reader to file mapping table full - waiting\n"));
75       npth_sleep (2);
76     }
77 }
78
79 /* Scan the table for an entry matching READER, remove that entry and
80    return the associated file pointer. */
81 static struct reader_cb_context_s *
82 get_file_reader (ksba_reader_t reader)
83 {
84   struct reader_cb_context_s *cb_ctx = NULL;
85   int i;
86
87   for (i=0; i < MAX_FILE_READER; i++)
88     if (file_reader_map[i].reader == reader)
89       {
90         cb_ctx = file_reader_map[i].cb_ctx;
91         file_reader_map[i].reader = NULL;
92         file_reader_map[i].cb_ctx = NULL;
93         break;
94       }
95   return cb_ctx;
96 }
97
98
99
100 static int
101 my_es_read (void *opaque, char *buffer, size_t nbytes, size_t *nread)
102 {
103   struct reader_cb_context_s *cb_ctx = opaque;
104   int result;
105
106   result = es_read (cb_ctx->fp, buffer, nbytes, nread);
107   if (result)
108     return result;
109   /* Fixme we should check whether the semantics of es_read are okay
110      and well defined.  I have some doubts.  */
111   if (nbytes && !*nread && es_feof (cb_ctx->fp))
112     return gpg_error (GPG_ERR_EOF);
113   if (!nread && es_ferror (cb_ctx->fp))
114     return gpg_error (GPG_ERR_EIO);
115
116   if (!cb_ctx->checked && *nread)
117     {
118       int c = *(unsigned char *)buffer;
119
120       cb_ctx->checked = 1;
121       if ( ((c & 0xc0) >> 6) == 0 /* class: universal */
122            && (c & 0x1f) == 16    /* sequence */
123            && (c & 0x20)          /* is constructed */ )
124         ; /* Binary data.  */
125       else
126         {
127           cb_ctx->is_pem = 1;
128           b64dec_start (&cb_ctx->b64state, "");
129         }
130     }
131   if (cb_ctx->is_pem && *nread)
132     {
133       size_t nread2;
134
135       if (b64dec_proc (&cb_ctx->b64state, buffer, *nread, &nread2))
136         {
137           /* EOF from decoder. */
138           *nread = 0;
139           result = gpg_error (GPG_ERR_EOF);
140         }
141       else
142         *nread = nread2;
143     }
144
145   return result;
146 }
147
148
149 /* Fetch CRL from URL and return the entire CRL using new ksba reader
150    object in READER.  Note that this reader object should be closed
151    only using ldap_close_reader. */
152 gpg_error_t
153 crl_fetch (ctrl_t ctrl, const char *url, ksba_reader_t *reader)
154 {
155   gpg_error_t err;
156   parsed_uri_t uri;
157   char *free_this = NULL;
158   int redirects_left = 2; /* We allow for 2 redirect levels.  */
159
160 #ifndef USE_LDAP
161   (void)ctrl;
162 #endif
163
164   *reader = NULL;
165
166  once_more:
167   err = http_parse_uri (&uri, url, 0);
168   http_release_parsed_uri (uri);
169   if (err && url && !strncmp (url, "https:", 6))
170     {
171       /* Our HTTP code does not support TLS, thus we can't use this
172          scheme and it is frankly not useful for CRL retrieval anyway.
173          We resort to using http, assuming that the server also
174          provides plain http access. */
175       free_this = xtrymalloc (strlen (url) + 1);
176       if (free_this)
177         {
178           strcpy (stpcpy (free_this,"http:"), url+6);
179           err = http_parse_uri (&uri, free_this, 0);
180           http_release_parsed_uri (uri);
181           if (!err)
182             {
183               log_info (_("using \"http\" instead of \"https\"\n"));
184               url = free_this;
185             }
186         }
187     }
188   if (!err) /* Yes, our HTTP code groks that. */
189     {
190       http_t hd;
191
192       if (opt.disable_http)
193         {
194           log_error (_("CRL access not possible due to disabled %s\n"),
195                      "HTTP");
196           err = gpg_error (GPG_ERR_NOT_SUPPORTED);
197         }
198       else
199         err = http_open_document (&hd, url, NULL,
200                                   (opt.honor_http_proxy? HTTP_FLAG_TRY_PROXY:0)
201                                   |(DBG_LOOKUP? HTTP_FLAG_LOG_RESP:0),
202                                   opt.http_proxy, NULL, NULL, NULL);
203
204       switch ( err? 99999 : http_get_status_code (hd) )
205         {
206         case 200:
207           {
208             estream_t fp = http_get_read_ptr (hd);
209             struct reader_cb_context_s *cb_ctx;
210
211             cb_ctx = xtrycalloc (1, sizeof *cb_ctx);
212             if (!cb_ctx)
213               err = gpg_error_from_syserror ();
214             if (!err)
215               err = ksba_reader_new (reader);
216             if (!err)
217               {
218                 cb_ctx->fp = fp;
219                 err = ksba_reader_set_cb (*reader, &my_es_read, cb_ctx);
220               }
221             if (err)
222               {
223                 log_error (_("error initializing reader object: %s\n"),
224                            gpg_strerror (err));
225                 ksba_reader_release (*reader);
226                 *reader = NULL;
227                 http_close (hd, 0);
228               }
229             else
230               {
231                 /* The ksba reader misses a user pointer thus we need
232                    to come up with our own way of associating a file
233                    pointer (or well the callback context) with the
234                    reader.  It is only required when closing the
235                    reader thus there is no performance issue doing it
236                    this way.  FIXME: We now have a close notification
237                    which might be used here. */
238                 register_file_reader (*reader, cb_ctx);
239                 http_close (hd, 1);
240               }
241           }
242           break;
243
244         case 301: /* Redirection (perm.). */
245         case 302: /* Redirection (temp.). */
246           {
247             const char *s = http_get_header (hd, "Location");
248
249             log_info (_("URL '%s' redirected to '%s' (%u)\n"),
250                       url, s?s:"[none]", http_get_status_code (hd));
251             if (s && *s && redirects_left-- )
252               {
253                 xfree (free_this); url = NULL;
254                 free_this = xtrystrdup (s);
255                 if (!free_this)
256                   err = gpg_error_from_errno (errno);
257                 else
258                   {
259                     url = free_this;
260                     http_close (hd, 0);
261                     /* Note, that our implementation of redirection
262                        actually handles a redirect to LDAP.  */
263                     goto once_more;
264                   }
265               }
266             else
267               err = gpg_error (GPG_ERR_NO_DATA);
268             log_error (_("too many redirections\n")); /* Or no "Location". */
269             http_close (hd, 0);
270           }
271           break;
272
273         case 99999: /* Made up status code for error reporting.  */
274           log_error (_("error retrieving '%s': %s\n"),
275                      url, gpg_strerror (err));
276           break;
277
278         default:
279           log_error (_("error retrieving '%s': http status %u\n"),
280                      url, http_get_status_code (hd));
281           err = gpg_error (GPG_ERR_NO_DATA);
282           http_close (hd, 0);
283         }
284     }
285   else /* Let the LDAP code try other schemes. */
286     {
287       if (opt.disable_ldap)
288         {
289           log_error (_("CRL access not possible due to disabled %s\n"),
290                      "LDAP");
291           err = gpg_error (GPG_ERR_NOT_SUPPORTED);
292         }
293       else
294         {
295 #       if USE_LDAP
296           err = url_fetch_ldap (ctrl, url, NULL, 0, reader);
297 #       else /*!USE_LDAP*/
298           err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
299 #       endif /*!USE_LDAP*/
300         }
301     }
302
303   xfree (free_this);
304   return err;
305 }
306
307
308 /* Fetch CRL for ISSUER using a default server. Return the entire CRL
309    as a newly opened stream returned in R_FP. */
310 gpg_error_t
311 crl_fetch_default (ctrl_t ctrl, const char *issuer, ksba_reader_t *reader)
312 {
313   if (opt.disable_ldap)
314     {
315       log_error (_("CRL access not possible due to disabled %s\n"),
316                  "LDAP");
317       return gpg_error (GPG_ERR_NOT_SUPPORTED);
318     }
319 #if USE_LDAP
320   return attr_fetch_ldap (ctrl, issuer, "certificateRevocationList",
321                           reader);
322 #else
323   (void)ctrl;
324   (void)issuer;
325   (void)reader;
326   return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
327 #endif
328 }
329
330
331 /* Fetch a CA certificate for DN using the default server. This
332    function only initiates the fetch; fetch_next_cert must be used to
333    actually read the certificate; end_cert_fetch to end the
334    operation. */
335 gpg_error_t
336 ca_cert_fetch (ctrl_t ctrl, cert_fetch_context_t *context, const char *dn)
337 {
338   if (opt.disable_ldap)
339     {
340       log_error (_("CRL access not possible due to disabled %s\n"),
341                  "LDAP");
342       return gpg_error (GPG_ERR_NOT_SUPPORTED);
343     }
344 #if USE_LDAP
345   return start_default_fetch_ldap (ctrl, context, dn, "cACertificate");
346 #else
347   (void)ctrl;
348   (void)context;
349   (void)dn;
350   return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
351 #endif
352 }
353
354
355 gpg_error_t
356 start_cert_fetch (ctrl_t ctrl, cert_fetch_context_t *context,
357                   strlist_t patterns, const ldap_server_t server)
358 {
359   if (opt.disable_ldap)
360     {
361       log_error (_("certificate search not possible due to disabled %s\n"),
362                  "LDAP");
363       return gpg_error (GPG_ERR_NOT_SUPPORTED);
364     }
365 #if USE_LDAP
366   return start_cert_fetch_ldap (ctrl, context, patterns, server);
367 #else
368   (void)ctrl;
369   (void)context;
370   (void)patterns;
371   (void)server;
372   return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
373 #endif
374 }
375
376
377 gpg_error_t
378 fetch_next_cert (cert_fetch_context_t context,
379                  unsigned char **value, size_t * valuelen)
380 {
381 #if USE_LDAP
382   return fetch_next_cert_ldap (context, value, valuelen);
383 #else
384   (void)context;
385   (void)value;
386   (void)valuelen;
387   return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
388 #endif
389 }
390
391
392 /* Fetch the next data from CONTEXT, assuming it is a certificate and return
393    it as a cert object in R_CERT.  */
394 gpg_error_t
395 fetch_next_ksba_cert (cert_fetch_context_t context, ksba_cert_t *r_cert)
396 {
397   gpg_error_t err;
398   unsigned char *value;
399   size_t valuelen;
400   ksba_cert_t cert;
401
402   *r_cert = NULL;
403
404 #if USE_LDAP
405   err = fetch_next_cert_ldap (context, &value, &valuelen);
406   if (!err && !value)
407     err = gpg_error (GPG_ERR_BUG);
408 #else
409   (void)context;
410   err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
411 #endif
412   if (err)
413     return err;
414
415   err = ksba_cert_new (&cert);
416   if (err)
417     {
418       xfree (value);
419       return err;
420     }
421
422   err = ksba_cert_init_from_mem (cert, value, valuelen);
423   xfree (value);
424   if (err)
425     {
426       ksba_cert_release (cert);
427       return err;
428     }
429   *r_cert = cert;
430   return 0;
431 }
432
433
434 void
435 end_cert_fetch (cert_fetch_context_t context)
436 {
437 #if USE_LDAP
438   end_cert_fetch_ldap (context);
439 #else
440   (void)context;
441 #endif
442 }
443
444
445 /* Lookup a cert by it's URL.  */
446 gpg_error_t
447 fetch_cert_by_url (ctrl_t ctrl, const char *url,
448                    unsigned char **value, size_t *valuelen)
449 {
450   const unsigned char *cert_image;
451   size_t cert_image_n;
452   ksba_reader_t reader;
453   ksba_cert_t cert;
454   gpg_error_t err;
455
456   *value = NULL;
457   *valuelen = 0;
458   cert_image = NULL;
459   reader = NULL;
460   cert = NULL;
461
462 #if USE_LDAP
463   err = url_fetch_ldap (ctrl, url, NULL, 0, &reader);
464 #else
465   (void)ctrl;
466   (void)url;
467   err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
468 #endif /*USE_LDAP*/
469   if (err)
470     goto leave;
471
472   err = ksba_cert_new (&cert);
473   if (err)
474     goto leave;
475
476   err = ksba_cert_read_der (cert, reader);
477   if (err)
478     goto leave;
479
480   cert_image = ksba_cert_get_image (cert, &cert_image_n);
481   if (!cert_image || !cert_image_n)
482     {
483       err = gpg_error (GPG_ERR_INV_CERT_OBJ);
484       goto leave;
485     }
486
487   *value = xtrymalloc (cert_image_n);
488   if (!*value)
489     {
490       err = gpg_error_from_syserror ();
491       goto leave;
492     }
493
494   memcpy (*value, cert_image, cert_image_n);
495   *valuelen = cert_image_n;
496
497  leave:
498
499   ksba_cert_release (cert);
500 #if USE_LDAP
501   ldap_wrapper_release_context (reader);
502 #endif /*USE_LDAP*/
503
504   return err;
505 }
506
507 /* This function is to be used to close the reader object.  In
508    addition to running ksba_reader_release it also releases the LDAP
509    or HTTP contexts associated with that reader.  */
510 void
511 crl_close_reader (ksba_reader_t reader)
512 {
513   struct reader_cb_context_s *cb_ctx;
514
515   if (!reader)
516     return;
517
518   /* Check whether this is a HTTP one. */
519   cb_ctx = get_file_reader (reader);
520   if (cb_ctx)
521     {
522       /* This is an HTTP context. */
523       if (cb_ctx->fp)
524         es_fclose (cb_ctx->fp);
525       /* Release the base64 decoder state.  */
526       if (cb_ctx->is_pem)
527         b64dec_finish (&cb_ctx->b64state);
528       /* Release the callback context.  */
529       xfree (cb_ctx);
530     }
531   else /* This is an ldap wrapper context (Currently not used). */
532     {
533 #if USE_LDAP
534       ldap_wrapper_release_context (reader);
535 #endif /*USE_LDAP*/
536     }
537
538   /* Now get rid of the reader object. */
539   ksba_reader_release (reader);
540 }