Line data Source code
1 : /* ks-engine-http.c - HTTP OpenPGP key access
2 : * Copyright (C) 2011 Free Software Foundation, Inc.
3 : *
4 : * This file is part of GnuPG.
5 : *
6 : * GnuPG is free software; you can redistribute it and/or modify
7 : * it under the terms of the GNU General Public License as published by
8 : * the Free Software Foundation; either version 3 of the License, or
9 : * (at your option) any later version.
10 : *
11 : * GnuPG is distributed in the hope that it will be useful,
12 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : * GNU General Public License for more details.
15 : *
16 : * You should have received a copy of the GNU General Public License
17 : * along with this program; if not, see <http://www.gnu.org/licenses/>.
18 : */
19 :
20 : #include <config.h>
21 :
22 : #include <stdio.h>
23 : #include <stdlib.h>
24 : #include <string.h>
25 : #include <assert.h>
26 :
27 : #include "dirmngr.h"
28 : #include "misc.h"
29 : #include "ks-engine.h"
30 :
31 : /* How many redirections do we allow. */
32 : #define MAX_REDIRECTS 2
33 :
34 : /* Print a help output for the schemata supported by this module. */
35 : gpg_error_t
36 0 : ks_http_help (ctrl_t ctrl, parsed_uri_t uri)
37 : {
38 0 : const char const data[] =
39 : "Handler for HTTP URLs:\n"
40 : " http://\n"
41 : " https://\n"
42 : "Supported methods: fetch\n";
43 : gpg_error_t err;
44 :
45 0 : if (!uri)
46 0 : err = ks_print_help (ctrl, " http");
47 0 : else if (uri->is_http && strcmp (uri->scheme, "hkp"))
48 0 : err = ks_print_help (ctrl, data);
49 : else
50 0 : err = 0;
51 :
52 0 : return err;
53 : }
54 :
55 :
56 : /* Get the key from URL which is expected to specify a http style
57 : scheme. On success R_FP has an open stream to read the data. */
58 : gpg_error_t
59 0 : ks_http_fetch (ctrl_t ctrl, const char *url, estream_t *r_fp)
60 : {
61 : gpg_error_t err;
62 0 : http_session_t session = NULL;
63 0 : http_t http = NULL;
64 0 : int redirects_left = MAX_REDIRECTS;
65 0 : estream_t fp = NULL;
66 0 : char *request_buffer = NULL;
67 :
68 0 : err = http_session_new (&session, NULL);
69 0 : if (err)
70 0 : goto leave;
71 0 : http_session_set_log_cb (session, cert_log_cb);
72 :
73 0 : *r_fp = NULL;
74 : once_more:
75 0 : err = http_open (&http,
76 : HTTP_REQ_GET,
77 : url,
78 : /* httphost */ NULL,
79 : /* fixme: AUTH */ NULL,
80 0 : ((opt.honor_http_proxy? HTTP_FLAG_TRY_PROXY:0)
81 0 : | (opt.use_tor? HTTP_FLAG_FORCE_TOR:0)),
82 0 : ctrl->http_proxy,
83 : session,
84 : NULL,
85 : /*FIXME curl->srvtag*/NULL);
86 0 : if (!err)
87 : {
88 0 : fp = http_get_write_ptr (http);
89 : /* Avoid caches to get the most recent copy of the key. We set
90 : both the Pragma and Cache-Control versions of the header, so
91 : we're good with both HTTP 1.0 and 1.1. */
92 0 : es_fputs ("Pragma: no-cache\r\n"
93 : "Cache-Control: no-cache\r\n", fp);
94 0 : http_start_data (http);
95 0 : if (es_ferror (fp))
96 0 : err = gpg_error_from_syserror ();
97 : }
98 0 : if (err)
99 : {
100 : /* Fixme: After a redirection we show the old host name. */
101 0 : log_error (_("error connecting to '%s': %s\n"),
102 : url, gpg_strerror (err));
103 0 : goto leave;
104 : }
105 :
106 : /* Wait for the response. */
107 0 : dirmngr_tick (ctrl);
108 0 : err = http_wait_response (http);
109 0 : if (err)
110 : {
111 0 : log_error (_("error reading HTTP response for '%s': %s\n"),
112 : url, gpg_strerror (err));
113 0 : goto leave;
114 : }
115 :
116 0 : switch (http_get_status_code (http))
117 : {
118 : case 200:
119 0 : err = 0;
120 0 : break; /* Success. */
121 :
122 : case 301:
123 : case 302:
124 : case 307:
125 : {
126 0 : const char *s = http_get_header (http, "Location");
127 :
128 0 : log_info (_("URL '%s' redirected to '%s' (%u)\n"),
129 : url, s?s:"[none]", http_get_status_code (http));
130 0 : if (s && *s && redirects_left-- )
131 : {
132 0 : xfree (request_buffer);
133 0 : request_buffer = xtrystrdup (s);
134 0 : if (request_buffer)
135 : {
136 0 : url = request_buffer;
137 0 : http_close (http, 0);
138 0 : http = NULL;
139 0 : goto once_more;
140 : }
141 0 : err = gpg_error_from_syserror ();
142 : }
143 : else
144 0 : err = gpg_error (GPG_ERR_NO_DATA);
145 0 : log_error (_("too many redirections\n"));
146 : }
147 0 : goto leave;
148 :
149 : default:
150 0 : log_error (_("error accessing '%s': http status %u\n"),
151 : url, http_get_status_code (http));
152 0 : err = gpg_error (GPG_ERR_NO_DATA);
153 0 : goto leave;
154 : }
155 :
156 0 : fp = http_get_read_ptr (http);
157 0 : if (!fp)
158 : {
159 0 : err = gpg_error (GPG_ERR_BUG);
160 0 : goto leave;
161 : }
162 :
163 : /* Return the read stream and close the HTTP context. */
164 0 : *r_fp = fp;
165 0 : http_close (http, 1);
166 0 : http = NULL;
167 :
168 : leave:
169 0 : http_close (http, 0);
170 0 : http_session_release (session);
171 0 : xfree (request_buffer);
172 0 : return err;
173 : }
|