tools: Free variable before return
[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 #ifndef USE_LDAP
161   (void)ctrl;
162 #endif
163
164   *reader = NULL;
165
166   if (!url)
167     return gpg_error (GPG_ERR_INV_ARG);
168
169  once_more:
170   err = http_parse_uri (&uri, url, 0);
171   http_release_parsed_uri (uri);
172   if (err && !strncmp (url, "https:", 6))
173     {
174       /* Our HTTP code does not support TLS, thus we can't use this
175          scheme and it is frankly not useful for CRL retrieval anyway.
176          We resort to using http, assuming that the server also
177          provides plain http access. */
178       free_this = xtrymalloc (strlen (url) + 1);
179       if (free_this)
180         {
181           strcpy (stpcpy (free_this,"http:"), url+6);
182           err = http_parse_uri (&uri, free_this, 0);
183           http_release_parsed_uri (uri);
184           if (!err)
185             {
186               log_info (_("using \"http\" instead of \"https\"\n"));
187               url = free_this;
188             }
189         }
190     }
191   if (!err) /* Yes, our HTTP code groks that. */
192     {
193       http_t hd;
194
195       if (opt.disable_http)
196         {
197           log_error (_("CRL access not possible due to disabled %s\n"),
198                      "HTTP");
199           err = gpg_error (GPG_ERR_NOT_SUPPORTED);
200         }
201       else
202         err = http_open_document (&hd, url, NULL,
203                                   (opt.honor_http_proxy? HTTP_FLAG_TRY_PROXY:0)
204                                   |(DBG_LOOKUP? HTTP_FLAG_LOG_RESP:0),
205                                   opt.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
297         {
298 #       if USE_LDAP
299           err = url_fetch_ldap (ctrl, url, NULL, 0, reader);
300 #       else /*!USE_LDAP*/
301           err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
302 #       endif /*!USE_LDAP*/
303         }
304     }
305
306   xfree (free_this);
307   return err;
308 }
309
310
311 /* Fetch CRL for ISSUER using a default server. Return the entire CRL
312    as a newly opened stream returned in R_FP. */
313 gpg_error_t
314 crl_fetch_default (ctrl_t ctrl, const char *issuer, ksba_reader_t *reader)
315 {
316   if (opt.disable_ldap)
317     {
318       log_error (_("CRL access not possible due to disabled %s\n"),
319                  "LDAP");
320       return gpg_error (GPG_ERR_NOT_SUPPORTED);
321     }
322 #if USE_LDAP
323   return attr_fetch_ldap (ctrl, issuer, "certificateRevocationList",
324                           reader);
325 #else
326   (void)ctrl;
327   (void)issuer;
328   (void)reader;
329   return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
330 #endif
331 }
332
333
334 /* Fetch a CA certificate for DN using the default server. This
335    function only initiates the fetch; fetch_next_cert must be used to
336    actually read the certificate; end_cert_fetch to end the
337    operation. */
338 gpg_error_t
339 ca_cert_fetch (ctrl_t ctrl, cert_fetch_context_t *context, const char *dn)
340 {
341   if (opt.disable_ldap)
342     {
343       log_error (_("CRL access not possible due to disabled %s\n"),
344                  "LDAP");
345       return gpg_error (GPG_ERR_NOT_SUPPORTED);
346     }
347 #if USE_LDAP
348   return start_default_fetch_ldap (ctrl, context, dn, "cACertificate");
349 #else
350   (void)ctrl;
351   (void)context;
352   (void)dn;
353   return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
354 #endif
355 }
356
357
358 gpg_error_t
359 start_cert_fetch (ctrl_t ctrl, cert_fetch_context_t *context,
360                   strlist_t patterns, const ldap_server_t server)
361 {
362   if (opt.disable_ldap)
363     {
364       log_error (_("certificate search not possible due to disabled %s\n"),
365                  "LDAP");
366       return gpg_error (GPG_ERR_NOT_SUPPORTED);
367     }
368 #if USE_LDAP
369   return start_cert_fetch_ldap (ctrl, context, patterns, server);
370 #else
371   (void)ctrl;
372   (void)context;
373   (void)patterns;
374   (void)server;
375   return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
376 #endif
377 }
378
379
380 gpg_error_t
381 fetch_next_cert (cert_fetch_context_t context,
382                  unsigned char **value, size_t * valuelen)
383 {
384 #if USE_LDAP
385   return fetch_next_cert_ldap (context, value, valuelen);
386 #else
387   (void)context;
388   (void)value;
389   (void)valuelen;
390   return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
391 #endif
392 }
393
394
395 /* Fetch the next data from CONTEXT, assuming it is a certificate and return
396    it as a cert object in R_CERT.  */
397 gpg_error_t
398 fetch_next_ksba_cert (cert_fetch_context_t context, ksba_cert_t *r_cert)
399 {
400   gpg_error_t err;
401   unsigned char *value;
402   size_t valuelen;
403   ksba_cert_t cert;
404
405   *r_cert = NULL;
406
407 #if USE_LDAP
408   err = fetch_next_cert_ldap (context, &value, &valuelen);
409   if (!err && !value)
410     err = gpg_error (GPG_ERR_BUG);
411 #else
412   (void)context;
413   err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
414 #endif
415   if (err)
416     return err;
417
418   err = ksba_cert_new (&cert);
419   if (err)
420     {
421       xfree (value);
422       return err;
423     }
424
425   err = ksba_cert_init_from_mem (cert, value, valuelen);
426   xfree (value);
427   if (err)
428     {
429       ksba_cert_release (cert);
430       return err;
431     }
432   *r_cert = cert;
433   return 0;
434 }
435
436
437 void
438 end_cert_fetch (cert_fetch_context_t context)
439 {
440 #if USE_LDAP
441   end_cert_fetch_ldap (context);
442 #else
443   (void)context;
444 #endif
445 }
446
447
448 /* Lookup a cert by it's URL.  */
449 gpg_error_t
450 fetch_cert_by_url (ctrl_t ctrl, const char *url,
451                    unsigned char **value, size_t *valuelen)
452 {
453   const unsigned char *cert_image;
454   size_t cert_image_n;
455   ksba_reader_t reader;
456   ksba_cert_t cert;
457   gpg_error_t err;
458
459   *value = NULL;
460   *valuelen = 0;
461   cert_image = NULL;
462   reader = NULL;
463   cert = NULL;
464
465 #if USE_LDAP
466   err = url_fetch_ldap (ctrl, url, NULL, 0, &reader);
467 #else
468   (void)ctrl;
469   (void)url;
470   err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
471 #endif /*USE_LDAP*/
472   if (err)
473     goto leave;
474
475   err = ksba_cert_new (&cert);
476   if (err)
477     goto leave;
478
479   err = ksba_cert_read_der (cert, reader);
480   if (err)
481     goto leave;
482
483   cert_image = ksba_cert_get_image (cert, &cert_image_n);
484   if (!cert_image || !cert_image_n)
485     {
486       err = gpg_error (GPG_ERR_INV_CERT_OBJ);
487       goto leave;
488     }
489
490   *value = xtrymalloc (cert_image_n);
491   if (!*value)
492     {
493       err = gpg_error_from_syserror ();
494       goto leave;
495     }
496
497   memcpy (*value, cert_image, cert_image_n);
498   *valuelen = cert_image_n;
499
500  leave:
501
502   ksba_cert_release (cert);
503 #if USE_LDAP
504   ldap_wrapper_release_context (reader);
505 #endif /*USE_LDAP*/
506
507   return err;
508 }
509
510 /* This function is to be used to close the reader object.  In
511    addition to running ksba_reader_release it also releases the LDAP
512    or HTTP contexts associated with that reader.  */
513 void
514 crl_close_reader (ksba_reader_t reader)
515 {
516   struct reader_cb_context_s *cb_ctx;
517
518   if (!reader)
519     return;
520
521   /* Check whether this is a HTTP one. */
522   cb_ctx = get_file_reader (reader);
523   if (cb_ctx)
524     {
525       /* This is an HTTP context. */
526       if (cb_ctx->fp)
527         es_fclose (cb_ctx->fp);
528       /* Release the base64 decoder state.  */
529       if (cb_ctx->is_pem)
530         b64dec_finish (&cb_ctx->b64state);
531       /* Release the callback context.  */
532       xfree (cb_ctx);
533     }
534   else /* This is an ldap wrapper context (Currently not used). */
535     {
536 #if USE_LDAP
537       ldap_wrapper_release_context (reader);
538 #endif /*USE_LDAP*/
539     }
540
541   /* Now get rid of the reader object. */
542   ksba_reader_release (reader);
543 }