Typo fix
[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
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       pth_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);
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);
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.  */
232                 register_file_reader (*reader, cb_ctx);
233                 http_close (hd, 1);
234               }
235           }
236           break;
237         
238         case 301: /* Redirection (perm.). */
239         case 302: /* Redirection (temp.). */
240           {
241             const char *s = http_get_header (hd, "Location");
242
243             log_info (_("URL `%s' redirected to `%s' (%u)\n"),
244                       url, s?s:"[none]", http_get_status_code (hd));
245             if (s && *s && redirects_left-- )
246               {
247                 xfree (free_this); url = NULL;
248                 free_this = xtrystrdup (s);
249                 if (!free_this)
250                   err = gpg_error_from_errno (errno);
251                 else
252                   {
253                     url = free_this;
254                     http_close (hd, 0);
255                     /* Note, that our implementation of redirection
256                        actually handles a redirect to LDAP.  */
257                     goto once_more;
258                   }
259               }
260             else
261               err = gpg_error (GPG_ERR_NO_DATA);
262             log_error (_("too many redirections\n")); /* Or no "Location". */
263             http_close (hd, 0);
264           }
265           break;
266   
267         case 99999: /* Made up status code for error reporting.  */
268           log_error (_("error retrieving `%s': %s\n"),
269                      url, gpg_strerror (err));
270           break;
271
272         default:
273           log_error (_("error retrieving `%s': http status %u\n"),
274                      url, http_get_status_code (hd));
275           err = gpg_error (GPG_ERR_NO_DATA);
276           http_close (hd, 0);
277         }
278     }
279   else /* Let the LDAP code try other schemes. */
280     {
281       if (opt.disable_ldap)
282         {
283           log_error (_("CRL access not possible due to disabled %s\n"),
284                      "LDAP");
285           err = gpg_error (GPG_ERR_NOT_SUPPORTED);
286         }
287       else
288         err = url_fetch_ldap (ctrl, url, NULL, 0, reader);
289     }
290
291   xfree (free_this);
292   return err;
293 }
294
295
296 /* Fetch CRL for ISSUER using a default server. Return the entire CRL
297    as a newly opened stream returned in R_FP. */
298 gpg_error_t
299 crl_fetch_default (ctrl_t ctrl, const char *issuer, ksba_reader_t *reader)
300 {
301   if (opt.disable_ldap)
302     {
303       log_error (_("CRL access not possible due to disabled %s\n"),
304                  "LDAP");
305       return gpg_error (GPG_ERR_NOT_SUPPORTED);
306     }
307   return attr_fetch_ldap (ctrl, issuer, "certificateRevocationList",
308                           reader);
309 }
310
311
312 /* Fetch a CA certificate for DN using the default server. This
313    function only initiates the fetch; fetch_next_cert must be used to
314    actually read the certificate; end_cert_fetch to end the
315    operation. */
316 gpg_error_t
317 ca_cert_fetch (ctrl_t ctrl, cert_fetch_context_t *context, const char *dn)
318 {
319   if (opt.disable_ldap)
320     {
321       log_error (_("CRL access not possible due to disabled %s\n"),
322                  "LDAP");
323       return gpg_error (GPG_ERR_NOT_SUPPORTED);
324     }
325   return start_default_fetch_ldap (ctrl, context, dn, "cACertificate");
326 }
327
328
329 gpg_error_t
330 start_cert_fetch (ctrl_t ctrl, cert_fetch_context_t *context,
331                   strlist_t patterns, const ldap_server_t server)
332 {
333   if (opt.disable_ldap)
334     {
335       log_error (_("certificate search not possible due to disabled %s\n"),
336                  "LDAP");
337       return gpg_error (GPG_ERR_NOT_SUPPORTED);
338     }
339   return start_cert_fetch_ldap (ctrl, context, patterns, server);
340 }
341
342
343 gpg_error_t
344 fetch_next_cert (cert_fetch_context_t context,
345                  unsigned char **value, size_t * valuelen)
346 {
347   return fetch_next_cert_ldap (context, value, valuelen);
348 }
349
350
351 /* Fetch the next data from CONTEXT, assuming it is a certificate and return
352    it as a cert object in R_CERT.  */
353 gpg_error_t
354 fetch_next_ksba_cert (cert_fetch_context_t context, ksba_cert_t *r_cert)
355 {
356   gpg_error_t err;
357   unsigned char *value;
358   size_t valuelen;
359   ksba_cert_t cert;
360   
361   *r_cert = NULL;
362
363   err = fetch_next_cert_ldap (context, &value, &valuelen);
364   if (!err && !value)
365     err = gpg_error (GPG_ERR_BUG);
366   if (err)
367     return err;
368
369   err = ksba_cert_new (&cert);
370   if (err)
371     {
372       xfree (value);
373       return err;
374     }
375
376   err = ksba_cert_init_from_mem (cert, value, valuelen);
377   xfree (value);
378   if (err)
379     {
380       ksba_cert_release (cert);
381       return err;
382     }
383   *r_cert = cert;
384   return 0;
385 }
386
387
388 void
389 end_cert_fetch (cert_fetch_context_t context)
390 {
391   return end_cert_fetch_ldap (context);
392 }
393
394
395 /* Lookup a cert by it's URL.  */
396 gpg_error_t
397 fetch_cert_by_url (ctrl_t ctrl, const char *url,
398                    unsigned char **value, size_t *valuelen)
399 {
400   const unsigned char *cert_image;
401   size_t cert_image_n;
402   ksba_reader_t reader;
403   ksba_cert_t cert;
404   gpg_error_t err;
405
406   *value = NULL;
407   *valuelen = 0;
408   cert_image = NULL;
409   reader = NULL;
410   cert = NULL;
411
412   err = url_fetch_ldap (ctrl, url, NULL, 0, &reader);
413   if (err)
414     goto leave;
415
416   err = ksba_cert_new (&cert);
417   if (err)
418     goto leave;
419
420   err = ksba_cert_read_der (cert, reader);
421   if (err)
422     goto leave;
423
424   cert_image = ksba_cert_get_image (cert, &cert_image_n);
425   if (!cert_image || !cert_image_n)
426     {
427       err = gpg_error (GPG_ERR_INV_CERT_OBJ);
428       goto leave;
429     }
430
431   *value = xtrymalloc (cert_image_n);
432   if (!*value)
433     {
434       err = gpg_error_from_syserror ();
435       goto leave;
436     }
437
438   memcpy (*value, cert_image, cert_image_n);
439   *valuelen = cert_image_n;
440
441  leave:
442
443   ksba_cert_release (cert);
444   ldap_wrapper_release_context (reader);
445
446   return err;  
447 }
448
449 /* This function is to be used to close the reader object.  In
450    addition to running ksba_reader_release it also releases the LDAP
451    or HTTP contexts associated with that reader.  */
452 void
453 crl_close_reader (ksba_reader_t reader)
454 {
455   struct reader_cb_context_s *cb_ctx;
456
457   if (!reader)
458     return;
459
460   /* Check whether this is a HTTP one. */
461   cb_ctx = get_file_reader (reader);
462   if (cb_ctx)
463     {
464       /* This is an HTTP context. */
465       if (cb_ctx->fp) 
466         es_fclose (cb_ctx->fp);
467       /* Release the base64 decoder state.  */
468       if (cb_ctx->is_pem)
469         b64dec_finish (&cb_ctx->b64state);
470       /* Release the callback context.  */
471       xfree (cb_ctx);
472     }
473   else /* This is an ldap wrapper context (Currently not used). */
474     ldap_wrapper_release_context (reader);
475
476   /* Now get rid of the reader object. */
477   ksba_reader_release (reader);
478 }