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