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