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