common: Add an assuan logging monitor.
[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   *reader = NULL;
161
162   if (!url)
163     return gpg_error (GPG_ERR_INV_ARG);
164
165  once_more:
166   err = http_parse_uri (&uri, url, 0);
167   http_release_parsed_uri (uri);
168   if (err && !strncmp (url, "https:", 6))
169     {
170       /* Our HTTP code does not support TLS, thus we can't use this
171          scheme and it is frankly not useful for CRL retrieval anyway.
172          We resort to using http, assuming that the server also
173          provides plain http access. */
174       free_this = xtrymalloc (strlen (url) + 1);
175       if (free_this)
176         {
177           strcpy (stpcpy (free_this,"http:"), url+6);
178           err = http_parse_uri (&uri, free_this, 0);
179           http_release_parsed_uri (uri);
180           if (!err)
181             {
182               log_info (_("using \"http\" instead of \"https\"\n"));
183               url = free_this;
184             }
185         }
186     }
187   if (!err) /* Yes, our HTTP code groks that. */
188     {
189       http_t hd;
190
191       if (opt.disable_http)
192         {
193           log_error (_("CRL access not possible due to disabled %s\n"),
194                      "HTTP");
195           err = gpg_error (GPG_ERR_NOT_SUPPORTED);
196         }
197       else
198         err = http_open_document (&hd, url, NULL,
199                                   ((opt.honor_http_proxy? HTTP_FLAG_TRY_PROXY:0)
200                                    |(DBG_LOOKUP? HTTP_FLAG_LOG_RESP:0)
201                                    |(opt.use_tor? HTTP_FLAG_FORCE_TOR:0)),
202                                   ctrl->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 if (opt.use_tor)
294         {
295           /* For now we do not support LDAP over Tor.  */
296           log_error (_("CRL access not possible due to Tor mode\n"));
297           err = gpg_error (GPG_ERR_NOT_SUPPORTED);
298         }
299       else
300         {
301 #       if USE_LDAP
302           err = url_fetch_ldap (ctrl, url, NULL, 0, reader);
303 #       else /*!USE_LDAP*/
304           err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
305 #       endif /*!USE_LDAP*/
306         }
307     }
308
309   xfree (free_this);
310   return err;
311 }
312
313
314 /* Fetch CRL for ISSUER using a default server. Return the entire CRL
315    as a newly opened stream returned in R_FP. */
316 gpg_error_t
317 crl_fetch_default (ctrl_t ctrl, const char *issuer, ksba_reader_t *reader)
318 {
319   if (opt.use_tor)
320     {
321       /* For now we do not support LDAP over Tor.  */
322       log_error (_("CRL access not possible due to Tor mode\n"));
323       return gpg_error (GPG_ERR_NOT_SUPPORTED);
324     }
325   if (opt.disable_ldap)
326     {
327       log_error (_("CRL access not possible due to disabled %s\n"),
328                  "LDAP");
329       return gpg_error (GPG_ERR_NOT_SUPPORTED);
330     }
331
332 #if USE_LDAP
333   return attr_fetch_ldap (ctrl, issuer, "certificateRevocationList",
334                           reader);
335 #else
336   (void)ctrl;
337   (void)issuer;
338   (void)reader;
339   return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
340 #endif
341 }
342
343
344 /* Fetch a CA certificate for DN using the default server. This
345    function only initiates the fetch; fetch_next_cert must be used to
346    actually read the certificate; end_cert_fetch to end the
347    operation. */
348 gpg_error_t
349 ca_cert_fetch (ctrl_t ctrl, cert_fetch_context_t *context, const char *dn)
350 {
351   if (opt.use_tor)
352     {
353       /* For now we do not support LDAP over Tor.  */
354       log_error (_("CRL access not possible due to Tor mode\n"));
355       return gpg_error (GPG_ERR_NOT_SUPPORTED);
356     }
357   if (opt.disable_ldap)
358     {
359       log_error (_("CRL access not possible due to disabled %s\n"),
360                  "LDAP");
361       return gpg_error (GPG_ERR_NOT_SUPPORTED);
362     }
363 #if USE_LDAP
364   return start_default_fetch_ldap (ctrl, context, dn, "cACertificate");
365 #else
366   (void)ctrl;
367   (void)context;
368   (void)dn;
369   return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
370 #endif
371 }
372
373
374 gpg_error_t
375 start_cert_fetch (ctrl_t ctrl, cert_fetch_context_t *context,
376                   strlist_t patterns, const ldap_server_t server)
377 {
378   if (opt.use_tor)
379     {
380       /* For now we do not support LDAP over Tor.  */
381       log_error (_("CRL access not possible due to Tor mode\n"));
382       return gpg_error (GPG_ERR_NOT_SUPPORTED);
383     }
384   if (opt.disable_ldap)
385     {
386       log_error (_("certificate search not possible due to disabled %s\n"),
387                  "LDAP");
388       return gpg_error (GPG_ERR_NOT_SUPPORTED);
389     }
390 #if USE_LDAP
391   return start_cert_fetch_ldap (ctrl, context, patterns, server);
392 #else
393   (void)ctrl;
394   (void)context;
395   (void)patterns;
396   (void)server;
397   return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
398 #endif
399 }
400
401
402 gpg_error_t
403 fetch_next_cert (cert_fetch_context_t context,
404                  unsigned char **value, size_t * valuelen)
405 {
406 #if USE_LDAP
407   return fetch_next_cert_ldap (context, value, valuelen);
408 #else
409   (void)context;
410   (void)value;
411   (void)valuelen;
412   return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
413 #endif
414 }
415
416
417 /* Fetch the next data from CONTEXT, assuming it is a certificate and return
418    it as a cert object in R_CERT.  */
419 gpg_error_t
420 fetch_next_ksba_cert (cert_fetch_context_t context, ksba_cert_t *r_cert)
421 {
422   gpg_error_t err;
423   unsigned char *value;
424   size_t valuelen;
425   ksba_cert_t cert;
426
427   *r_cert = NULL;
428
429 #if USE_LDAP
430   err = fetch_next_cert_ldap (context, &value, &valuelen);
431   if (!err && !value)
432     err = gpg_error (GPG_ERR_BUG);
433 #else
434   (void)context;
435   err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
436 #endif
437   if (err)
438     return err;
439
440   err = ksba_cert_new (&cert);
441   if (err)
442     {
443       xfree (value);
444       return err;
445     }
446
447   err = ksba_cert_init_from_mem (cert, value, valuelen);
448   xfree (value);
449   if (err)
450     {
451       ksba_cert_release (cert);
452       return err;
453     }
454   *r_cert = cert;
455   return 0;
456 }
457
458
459 void
460 end_cert_fetch (cert_fetch_context_t context)
461 {
462 #if USE_LDAP
463   end_cert_fetch_ldap (context);
464 #else
465   (void)context;
466 #endif
467 }
468
469
470 /* Lookup a cert by it's URL.  */
471 gpg_error_t
472 fetch_cert_by_url (ctrl_t ctrl, const char *url,
473                    unsigned char **value, size_t *valuelen)
474 {
475   const unsigned char *cert_image;
476   size_t cert_image_n;
477   ksba_reader_t reader;
478   ksba_cert_t cert;
479   gpg_error_t err;
480
481   *value = NULL;
482   *valuelen = 0;
483   cert_image = NULL;
484   reader = NULL;
485   cert = NULL;
486
487 #if USE_LDAP
488   err = url_fetch_ldap (ctrl, url, NULL, 0, &reader);
489 #else
490   (void)ctrl;
491   (void)url;
492   err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
493 #endif /*USE_LDAP*/
494   if (err)
495     goto leave;
496
497   err = ksba_cert_new (&cert);
498   if (err)
499     goto leave;
500
501   err = ksba_cert_read_der (cert, reader);
502   if (err)
503     goto leave;
504
505   cert_image = ksba_cert_get_image (cert, &cert_image_n);
506   if (!cert_image || !cert_image_n)
507     {
508       err = gpg_error (GPG_ERR_INV_CERT_OBJ);
509       goto leave;
510     }
511
512   *value = xtrymalloc (cert_image_n);
513   if (!*value)
514     {
515       err = gpg_error_from_syserror ();
516       goto leave;
517     }
518
519   memcpy (*value, cert_image, cert_image_n);
520   *valuelen = cert_image_n;
521
522  leave:
523
524   ksba_cert_release (cert);
525 #if USE_LDAP
526   ldap_wrapper_release_context (reader);
527 #endif /*USE_LDAP*/
528
529   return err;
530 }
531
532 /* This function is to be used to close the reader object.  In
533    addition to running ksba_reader_release it also releases the LDAP
534    or HTTP contexts associated with that reader.  */
535 void
536 crl_close_reader (ksba_reader_t reader)
537 {
538   struct reader_cb_context_s *cb_ctx;
539
540   if (!reader)
541     return;
542
543   /* Check whether this is a HTTP one. */
544   cb_ctx = get_file_reader (reader);
545   if (cb_ctx)
546     {
547       /* This is an HTTP context. */
548       if (cb_ctx->fp)
549         es_fclose (cb_ctx->fp);
550       /* Release the base64 decoder state.  */
551       if (cb_ctx->is_pem)
552         b64dec_finish (&cb_ctx->b64state);
553       /* Release the callback context.  */
554       xfree (cb_ctx);
555     }
556   else /* This is an ldap wrapper context (Currently not used). */
557     {
558 #if USE_LDAP
559       ldap_wrapper_release_context (reader);
560 #endif /*USE_LDAP*/
561     }
562
563   /* Now get rid of the reader object. */
564   ksba_reader_release (reader);
565 }