More work on the dirmngr. It now builds for W32 and W32CE and quick
[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 <pth.h>
26
27 #include "crlfetch.h"
28 #include "dirmngr.h"
29 #include "misc.h"
30 #include "http.h"
31
32 #include "estream.h"
33 #include "ldap-wrapper.h"
34
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       pth_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  once_more:
163   err = http_parse_uri (&uri, url);
164   http_release_parsed_uri (uri);
165   if (err && url && !strncmp (url, "https:", 6))
166     {
167       /* Our HTTP code does not support TLS, thus we can't use this
168          scheme and it is frankly not useful for CRL retrieval anyway.
169          We resort to using http, assuming that the server also
170          provides plain http access. */
171       free_this = xtrymalloc (strlen (url) + 1);
172       if (free_this)
173         {
174           strcpy (stpcpy (free_this,"http:"), url+6);
175           err = http_parse_uri (&uri, free_this);
176           http_release_parsed_uri (uri);
177           if (!err)
178             {
179               log_info (_("using \"http\" instead of \"https\"\n"));
180               url = free_this;
181             }
182         }
183     }
184   if (!err) /* Yes, our HTTP code groks that. */
185     {
186       http_t hd;
187
188       if (opt.disable_http)
189         {
190           log_error (_("CRL access not possible due to disabled %s\n"),
191                      "HTTP");
192           err = gpg_error (GPG_ERR_NOT_SUPPORTED);
193         }
194       else
195         err = http_open_document (&hd, url, NULL,
196                                   (opt.honor_http_proxy? HTTP_FLAG_TRY_PROXY:0)
197                                   |(DBG_LOOKUP? HTTP_FLAG_LOG_RESP:0), 
198                                   opt.http_proxy, NULL, NULL, NULL);
199
200       switch ( err? 99999 : http_get_status_code (hd) )
201         {
202         case 200:
203           {
204             estream_t fp = http_get_read_ptr (hd);
205             struct reader_cb_context_s *cb_ctx;
206
207             cb_ctx = xtrycalloc (1, sizeof *cb_ctx);
208             if (!cb_ctx)
209               err = gpg_error_from_syserror ();
210             if (!err)
211               err = ksba_reader_new (reader);
212             if (!err)
213               {
214                 cb_ctx->fp = fp;
215                 err = ksba_reader_set_cb (*reader, &my_es_read, cb_ctx);
216               }
217             if (err)
218               {
219                 log_error (_("error initializing reader object: %s\n"),
220                            gpg_strerror (err));
221                 ksba_reader_release (*reader);
222                 *reader = NULL;
223                 http_close (hd, 0);
224               }
225             else
226               {
227                 /* The ksba reader misses a user pointer thus we need
228                    to come up with our own way of associating a file
229                    pointer (or well the callback context) with the
230                    reader.  It is only required when closing the
231                    reader thus there is no performance issue doing it
232                    this way.  FIXME: We now have a close notification
233                    which might be used here. */
234                 register_file_reader (*reader, cb_ctx);
235                 http_close (hd, 1);
236               }
237           }
238           break;
239         
240         case 301: /* Redirection (perm.). */
241         case 302: /* Redirection (temp.). */
242           {
243             const char *s = http_get_header (hd, "Location");
244
245             log_info (_("URL `%s' redirected to `%s' (%u)\n"),
246                       url, s?s:"[none]", http_get_status_code (hd));
247             if (s && *s && redirects_left-- )
248               {
249                 xfree (free_this); url = NULL;
250                 free_this = xtrystrdup (s);
251                 if (!free_this)
252                   err = gpg_error_from_errno (errno);
253                 else
254                   {
255                     url = free_this;
256                     http_close (hd, 0);
257                     /* Note, that our implementation of redirection
258                        actually handles a redirect to LDAP.  */
259                     goto once_more;
260                   }
261               }
262             else
263               err = gpg_error (GPG_ERR_NO_DATA);
264             log_error (_("too many redirections\n")); /* Or no "Location". */
265             http_close (hd, 0);
266           }
267           break;
268   
269         case 99999: /* Made up status code for error reporting.  */
270           log_error (_("error retrieving `%s': %s\n"),
271                      url, gpg_strerror (err));
272           break;
273
274         default:
275           log_error (_("error retrieving `%s': http status %u\n"),
276                      url, http_get_status_code (hd));
277           err = gpg_error (GPG_ERR_NO_DATA);
278           http_close (hd, 0);
279         }
280     }
281   else /* Let the LDAP code try other schemes. */
282     {
283       if (opt.disable_ldap)
284         {
285           log_error (_("CRL access not possible due to disabled %s\n"),
286                      "LDAP");
287           err = gpg_error (GPG_ERR_NOT_SUPPORTED);
288         }
289       else
290         err = url_fetch_ldap (ctrl, url, NULL, 0, reader);
291     }
292
293   xfree (free_this);
294   return err;
295 }
296
297
298 /* Fetch CRL for ISSUER using a default server. Return the entire CRL
299    as a newly opened stream returned in R_FP. */
300 gpg_error_t
301 crl_fetch_default (ctrl_t ctrl, const char *issuer, ksba_reader_t *reader)
302 {
303   if (opt.disable_ldap)
304     {
305       log_error (_("CRL access not possible due to disabled %s\n"),
306                  "LDAP");
307       return gpg_error (GPG_ERR_NOT_SUPPORTED);
308     }
309   return attr_fetch_ldap (ctrl, issuer, "certificateRevocationList",
310                           reader);
311 }
312
313
314 /* Fetch a CA certificate for DN using the default server. This
315    function only initiates the fetch; fetch_next_cert must be used to
316    actually read the certificate; end_cert_fetch to end the
317    operation. */
318 gpg_error_t
319 ca_cert_fetch (ctrl_t ctrl, cert_fetch_context_t *context, const char *dn)
320 {
321   if (opt.disable_ldap)
322     {
323       log_error (_("CRL access not possible due to disabled %s\n"),
324                  "LDAP");
325       return gpg_error (GPG_ERR_NOT_SUPPORTED);
326     }
327   return start_default_fetch_ldap (ctrl, context, dn, "cACertificate");
328 }
329
330
331 gpg_error_t
332 start_cert_fetch (ctrl_t ctrl, cert_fetch_context_t *context,
333                   strlist_t patterns, const ldap_server_t server)
334 {
335   if (opt.disable_ldap)
336     {
337       log_error (_("certificate search not possible due to disabled %s\n"),
338                  "LDAP");
339       return gpg_error (GPG_ERR_NOT_SUPPORTED);
340     }
341   return start_cert_fetch_ldap (ctrl, context, patterns, server);
342 }
343
344
345 gpg_error_t
346 fetch_next_cert (cert_fetch_context_t context,
347                  unsigned char **value, size_t * valuelen)
348 {
349   return fetch_next_cert_ldap (context, value, valuelen);
350 }
351
352
353 /* Fetch the next data from CONTEXT, assuming it is a certificate and return
354    it as a cert object in R_CERT.  */
355 gpg_error_t
356 fetch_next_ksba_cert (cert_fetch_context_t context, ksba_cert_t *r_cert)
357 {
358   gpg_error_t err;
359   unsigned char *value;
360   size_t valuelen;
361   ksba_cert_t cert;
362   
363   *r_cert = NULL;
364
365   err = fetch_next_cert_ldap (context, &value, &valuelen);
366   if (!err && !value)
367     err = gpg_error (GPG_ERR_BUG);
368   if (err)
369     return err;
370
371   err = ksba_cert_new (&cert);
372   if (err)
373     {
374       xfree (value);
375       return err;
376     }
377
378   err = ksba_cert_init_from_mem (cert, value, valuelen);
379   xfree (value);
380   if (err)
381     {
382       ksba_cert_release (cert);
383       return err;
384     }
385   *r_cert = cert;
386   return 0;
387 }
388
389
390 void
391 end_cert_fetch (cert_fetch_context_t context)
392 {
393   return end_cert_fetch_ldap (context);
394 }
395
396
397 /* Lookup a cert by it's URL.  */
398 gpg_error_t
399 fetch_cert_by_url (ctrl_t ctrl, const char *url,
400                    unsigned char **value, size_t *valuelen)
401 {
402   const unsigned char *cert_image;
403   size_t cert_image_n;
404   ksba_reader_t reader;
405   ksba_cert_t cert;
406   gpg_error_t err;
407
408   *value = NULL;
409   *valuelen = 0;
410   cert_image = NULL;
411   reader = NULL;
412   cert = NULL;
413
414   err = url_fetch_ldap (ctrl, url, NULL, 0, &reader);
415   if (err)
416     goto leave;
417
418   err = ksba_cert_new (&cert);
419   if (err)
420     goto leave;
421
422   err = ksba_cert_read_der (cert, reader);
423   if (err)
424     goto leave;
425
426   cert_image = ksba_cert_get_image (cert, &cert_image_n);
427   if (!cert_image || !cert_image_n)
428     {
429       err = gpg_error (GPG_ERR_INV_CERT_OBJ);
430       goto leave;
431     }
432
433   *value = xtrymalloc (cert_image_n);
434   if (!*value)
435     {
436       err = gpg_error_from_syserror ();
437       goto leave;
438     }
439
440   memcpy (*value, cert_image, cert_image_n);
441   *valuelen = cert_image_n;
442
443  leave:
444
445   ksba_cert_release (cert);
446   ldap_wrapper_release_context (reader);
447
448   return err;  
449 }
450
451 /* This function is to be used to close the reader object.  In
452    addition to running ksba_reader_release it also releases the LDAP
453    or HTTP contexts associated with that reader.  */
454 void
455 crl_close_reader (ksba_reader_t reader)
456 {
457   struct reader_cb_context_s *cb_ctx;
458
459   if (!reader)
460     return;
461
462   /* Check whether this is a HTTP one. */
463   cb_ctx = get_file_reader (reader);
464   if (cb_ctx)
465     {
466       /* This is an HTTP context. */
467       if (cb_ctx->fp) 
468         es_fclose (cb_ctx->fp);
469       /* Release the base64 decoder state.  */
470       if (cb_ctx->is_pem)
471         b64dec_finish (&cb_ctx->b64state);
472       /* Release the callback context.  */
473       xfree (cb_ctx);
474     }
475   else /* This is an ldap wrapper context (Currently not used). */
476     ldap_wrapper_release_context (reader);
477
478   /* Now get rid of the reader object. */
479   ksba_reader_release (reader);
480 }