g10, sm, dirmngr, common: Add comment for fall through.
[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 <https://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       /* FIXME: We now support https.
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                                    |(dirmngr_use_tor()? HTTP_FLAG_FORCE_TOR:0)
203                                    |(opt.disable_ipv4? HTTP_FLAG_IGNORE_IPv4:0)
204                                    |(opt.disable_ipv6? HTTP_FLAG_IGNORE_IPv6:0)
205                                    ),
206                                   ctrl->http_proxy, NULL, NULL, NULL);
207
208       switch ( err? 99999 : http_get_status_code (hd) )
209         {
210         case 200:
211           {
212             estream_t fp = http_get_read_ptr (hd);
213             struct reader_cb_context_s *cb_ctx;
214
215             cb_ctx = xtrycalloc (1, sizeof *cb_ctx);
216             if (!cb_ctx)
217               err = gpg_error_from_syserror ();
218             if (!err)
219               err = ksba_reader_new (reader);
220             if (!err)
221               {
222                 cb_ctx->fp = fp;
223                 err = ksba_reader_set_cb (*reader, &my_es_read, cb_ctx);
224               }
225             if (err)
226               {
227                 log_error (_("error initializing reader object: %s\n"),
228                            gpg_strerror (err));
229                 ksba_reader_release (*reader);
230                 *reader = NULL;
231                 http_close (hd, 0);
232               }
233             else
234               {
235                 /* The ksba reader misses a user pointer thus we need
236                    to come up with our own way of associating a file
237                    pointer (or well the callback context) with the
238                    reader.  It is only required when closing the
239                    reader thus there is no performance issue doing it
240                    this way.  FIXME: We now have a close notification
241                    which might be used here. */
242                 register_file_reader (*reader, cb_ctx);
243                 http_close (hd, 1);
244               }
245           }
246           break;
247
248         case 301: /* Redirection (perm.). */
249         case 302: /* Redirection (temp.). */
250           {
251             const char *s = http_get_header (hd, "Location");
252
253             log_info (_("URL '%s' redirected to '%s' (%u)\n"),
254                       url, s?s:"[none]", http_get_status_code (hd));
255             if (s && *s && redirects_left-- )
256               {
257                 xfree (free_this); url = NULL;
258                 free_this = xtrystrdup (s);
259                 if (!free_this)
260                   err = gpg_error_from_errno (errno);
261                 else
262                   {
263                     url = free_this;
264                     http_close (hd, 0);
265                     /* Note, that our implementation of redirection
266                        actually handles a redirect to LDAP.  */
267                     goto once_more;
268                   }
269               }
270             else
271               err = gpg_error (GPG_ERR_NO_DATA);
272             log_error (_("too many redirections\n")); /* Or no "Location". */
273             http_close (hd, 0);
274           }
275           break;
276
277         case 99999: /* Made up status code for error reporting.  */
278           log_error (_("error retrieving '%s': %s\n"),
279                      url, gpg_strerror (err));
280           break;
281
282         default:
283           log_error (_("error retrieving '%s': http status %u\n"),
284                      url, http_get_status_code (hd));
285           err = gpg_error (GPG_ERR_NO_DATA);
286           http_close (hd, 0);
287         }
288     }
289   else /* Let the LDAP code try other schemes. */
290     {
291       if (opt.disable_ldap)
292         {
293           log_error (_("CRL access not possible due to disabled %s\n"),
294                      "LDAP");
295           err = gpg_error (GPG_ERR_NOT_SUPPORTED);
296         }
297       else if (dirmngr_use_tor ())
298         {
299           /* For now we do not support LDAP over Tor.  */
300           log_error (_("CRL access not possible due to Tor mode\n"));
301           err = gpg_error (GPG_ERR_NOT_SUPPORTED);
302         }
303       else
304         {
305 #       if USE_LDAP
306           err = url_fetch_ldap (ctrl, url, NULL, 0, reader);
307 #       else /*!USE_LDAP*/
308           err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
309 #       endif /*!USE_LDAP*/
310         }
311     }
312
313   xfree (free_this);
314   return err;
315 }
316
317
318 /* Fetch CRL for ISSUER using a default server. Return the entire CRL
319    as a newly opened stream returned in R_FP. */
320 gpg_error_t
321 crl_fetch_default (ctrl_t ctrl, const char *issuer, ksba_reader_t *reader)
322 {
323   if (dirmngr_use_tor ())
324     {
325       /* For now we do not support LDAP over Tor.  */
326       log_error (_("CRL access not possible due to Tor mode\n"));
327       return gpg_error (GPG_ERR_NOT_SUPPORTED);
328     }
329   if (opt.disable_ldap)
330     {
331       log_error (_("CRL access not possible due to disabled %s\n"),
332                  "LDAP");
333       return gpg_error (GPG_ERR_NOT_SUPPORTED);
334     }
335
336 #if USE_LDAP
337   return attr_fetch_ldap (ctrl, issuer, "certificateRevocationList",
338                           reader);
339 #else
340   (void)ctrl;
341   (void)issuer;
342   (void)reader;
343   return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
344 #endif
345 }
346
347
348 /* Fetch a CA certificate for DN using the default server.  This
349  * function only initiates the fetch; fetch_next_cert must be used to
350  * actually read the certificate; end_cert_fetch to end the
351  * operation.  */
352 gpg_error_t
353 ca_cert_fetch (ctrl_t ctrl, cert_fetch_context_t *context, const char *dn)
354 {
355   if (dirmngr_use_tor ())
356     {
357       /* For now we do not support LDAP over Tor.  */
358       log_error (_("CRL access not possible due to Tor mode\n"));
359       return gpg_error (GPG_ERR_NOT_SUPPORTED);
360     }
361   if (opt.disable_ldap)
362     {
363       log_error (_("CRL access not possible due to disabled %s\n"),
364                  "LDAP");
365       return gpg_error (GPG_ERR_NOT_SUPPORTED);
366     }
367 #if USE_LDAP
368   return start_default_fetch_ldap (ctrl, context, dn, "cACertificate");
369 #else
370   (void)ctrl;
371   (void)context;
372   (void)dn;
373   return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
374 #endif
375 }
376
377
378 gpg_error_t
379 start_cert_fetch (ctrl_t ctrl, cert_fetch_context_t *context,
380                   strlist_t patterns, const ldap_server_t server)
381 {
382   if (dirmngr_use_tor ())
383     {
384       /* For now we do not support LDAP over Tor.  */
385       log_error (_("CRL access not possible due to Tor mode\n"));
386       return gpg_error (GPG_ERR_NOT_SUPPORTED);
387     }
388   if (opt.disable_ldap)
389     {
390       log_error (_("certificate search not possible due to disabled %s\n"),
391                  "LDAP");
392       return gpg_error (GPG_ERR_NOT_SUPPORTED);
393     }
394 #if USE_LDAP
395   return start_cert_fetch_ldap (ctrl, context, patterns, server);
396 #else
397   (void)ctrl;
398   (void)context;
399   (void)patterns;
400   (void)server;
401   return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
402 #endif
403 }
404
405
406 gpg_error_t
407 fetch_next_cert (cert_fetch_context_t context,
408                  unsigned char **value, size_t * valuelen)
409 {
410 #if USE_LDAP
411   return fetch_next_cert_ldap (context, value, valuelen);
412 #else
413   (void)context;
414   (void)value;
415   (void)valuelen;
416   return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
417 #endif
418 }
419
420
421 /* Fetch the next data from CONTEXT, assuming it is a certificate and return
422  * it as a cert object in R_CERT.  */
423 gpg_error_t
424 fetch_next_ksba_cert (cert_fetch_context_t context, ksba_cert_t *r_cert)
425 {
426   gpg_error_t err;
427   unsigned char *value;
428   size_t valuelen;
429   ksba_cert_t cert;
430
431   *r_cert = NULL;
432
433 #if USE_LDAP
434   err = fetch_next_cert_ldap (context, &value, &valuelen);
435   if (!err && !value)
436     err = gpg_error (GPG_ERR_BUG);
437 #else
438   (void)context;
439   err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
440 #endif
441   if (err)
442     return err;
443
444   err = ksba_cert_new (&cert);
445   if (err)
446     {
447       xfree (value);
448       return err;
449     }
450
451   err = ksba_cert_init_from_mem (cert, value, valuelen);
452   xfree (value);
453   if (err)
454     {
455       ksba_cert_release (cert);
456       return err;
457     }
458   *r_cert = cert;
459   return 0;
460 }
461
462
463 void
464 end_cert_fetch (cert_fetch_context_t context)
465 {
466 #if USE_LDAP
467   end_cert_fetch_ldap (context);
468 #else
469   (void)context;
470 #endif
471 }
472
473
474 /* Lookup a cert by it's URL.  */
475 gpg_error_t
476 fetch_cert_by_url (ctrl_t ctrl, const char *url,
477                    unsigned char **value, size_t *valuelen)
478 {
479   const unsigned char *cert_image;
480   size_t cert_image_n;
481   ksba_reader_t reader;
482   ksba_cert_t cert;
483   gpg_error_t err;
484
485   *value = NULL;
486   *valuelen = 0;
487   cert_image = NULL;
488   reader = NULL;
489   cert = NULL;
490
491 #if USE_LDAP
492   err = url_fetch_ldap (ctrl, url, NULL, 0, &reader);
493 #else
494   (void)ctrl;
495   (void)url;
496   err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
497 #endif /*USE_LDAP*/
498   if (err)
499     goto leave;
500
501   err = ksba_cert_new (&cert);
502   if (err)
503     goto leave;
504
505   err = ksba_cert_read_der (cert, reader);
506   if (err)
507     goto leave;
508
509   cert_image = ksba_cert_get_image (cert, &cert_image_n);
510   if (!cert_image || !cert_image_n)
511     {
512       err = gpg_error (GPG_ERR_INV_CERT_OBJ);
513       goto leave;
514     }
515
516   *value = xtrymalloc (cert_image_n);
517   if (!*value)
518     {
519       err = gpg_error_from_syserror ();
520       goto leave;
521     }
522
523   memcpy (*value, cert_image, cert_image_n);
524   *valuelen = cert_image_n;
525
526  leave:
527
528   ksba_cert_release (cert);
529 #if USE_LDAP
530   ldap_wrapper_release_context (reader);
531 #endif /*USE_LDAP*/
532
533   return err;
534 }
535
536 /* This function is to be used to close the reader object.  In
537    addition to running ksba_reader_release it also releases the LDAP
538    or HTTP contexts associated with that reader.  */
539 void
540 crl_close_reader (ksba_reader_t reader)
541 {
542   struct reader_cb_context_s *cb_ctx;
543
544   if (!reader)
545     return;
546
547   /* Check whether this is a HTTP one. */
548   cb_ctx = get_file_reader (reader);
549   if (cb_ctx)
550     {
551       /* This is an HTTP context. */
552       if (cb_ctx->fp)
553         es_fclose (cb_ctx->fp);
554       /* Release the base64 decoder state.  */
555       if (cb_ctx->is_pem)
556         b64dec_finish (&cb_ctx->b64state);
557       /* Release the callback context.  */
558       xfree (cb_ctx);
559     }
560   else /* This is an ldap wrapper context (Currently not used). */
561     {
562 #if USE_LDAP
563       ldap_wrapper_release_context (reader);
564 #endif /*USE_LDAP*/
565     }
566
567   /* Now get rid of the reader object. */
568   ksba_reader_release (reader);
569 }