Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : HTTP library
5 :
6 : Copyright (C) 2019 Ralph Boehme <slow@samba.org>
7 :
8 : This program is free software; you can redistribute it and/or modify
9 : it under the terms of the GNU General Public License as published by
10 : the Free Software Foundation; either version 3 of the License, or
11 : (at your option) any later version.
12 :
13 : This program is distributed in the hope that it will be useful,
14 : but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 : GNU General Public License for more details.
17 :
18 : You should have received a copy of the GNU General Public License
19 : along with this program. If not, see <http://www.gnu.org/licenses/>.
20 : */
21 :
22 : #include "includes.h"
23 : #include "lib/util/tevent_ntstatus.h"
24 : #include "libcli/dns/dns_lookup.h"
25 : #include "lib/tsocket/tsocket.h"
26 : #include "lib/util/util_net.h"
27 : #include "lib/tls/tls.h"
28 : #include "lib/util/tevent_unix.h"
29 : #include "http.h"
30 : #include "http_internal.h"
31 :
32 : struct http_connect_state {
33 : struct tevent_context *ev;
34 : const char *http_server;
35 : const char *http_server_ip;
36 : uint16_t http_port;
37 : struct tsocket_address *local_address;
38 : struct tsocket_address *remote_address;
39 : struct cli_credentials *credentials;
40 : struct tstream_tls_params *tls_params;
41 :
42 : struct http_conn *http_conn;
43 : };
44 :
45 : static void http_connect_dns_done(struct tevent_req *subreq);
46 : static void http_connect_tcp_connect(struct tevent_req *req);
47 : static void http_connect_tcp_done(struct tevent_req *subreq);
48 : static void http_connect_tls_done(struct tevent_req *subreq);
49 :
50 34 : struct tevent_req *http_connect_send(TALLOC_CTX *mem_ctx,
51 : struct tevent_context *ev,
52 : const char *http_server,
53 : uint16_t http_port,
54 : struct cli_credentials *credentials,
55 : struct tstream_tls_params *tls_params)
56 : {
57 34 : struct tevent_req *req = NULL;
58 34 : struct tevent_req *subreq = NULL;
59 34 : struct http_connect_state *state = NULL;
60 0 : int ret;
61 :
62 34 : DBG_DEBUG("Connecting to [%s] over HTTP%s\n",
63 : http_server, tls_params != NULL ? "S" : "");
64 :
65 34 : req = tevent_req_create(mem_ctx, &state, struct http_connect_state);
66 34 : if (req == NULL) {
67 0 : return NULL;
68 : }
69 :
70 34 : *state = (struct http_connect_state) {
71 : .ev = ev,
72 : .http_port = http_port,
73 : .credentials = credentials,
74 : .tls_params = tls_params,
75 : };
76 :
77 34 : state->http_server = talloc_strdup(state, http_server);
78 34 : if (tevent_req_nomem(state->http_server, req)) {
79 0 : return tevent_req_post(req, ev);
80 : }
81 :
82 34 : state->http_conn = talloc_zero(state, struct http_conn);
83 34 : if (tevent_req_nomem(state->http_conn, req)) {
84 0 : return tevent_req_post(req, ev);
85 : }
86 :
87 34 : state->http_conn->send_queue = tevent_queue_create(state->http_conn,
88 : "HTTP send queue");
89 34 : if (tevent_req_nomem(state->http_conn->send_queue, req)) {
90 0 : return tevent_req_post(req, ev);
91 : }
92 :
93 34 : ret = tsocket_address_inet_from_strings(state,
94 : "ip",
95 : NULL,
96 : 0,
97 : &state->local_address);
98 34 : if (ret != 0) {
99 0 : tevent_req_error(req, errno);
100 0 : return tevent_req_post(req, ev);
101 : }
102 :
103 34 : if (!is_ipaddress(http_server)) {
104 0 : subreq = dns_lookup_send(state,
105 : ev,
106 : NULL,
107 : http_server,
108 : DNS_QCLASS_IN,
109 : DNS_QTYPE_A);
110 0 : if (tevent_req_nomem(subreq, req)) {
111 0 : return tevent_req_post(req, ev);
112 : }
113 0 : tevent_req_set_callback(subreq, http_connect_dns_done, req);
114 0 : return req;
115 : }
116 34 : state->http_server_ip = state->http_server;
117 :
118 34 : http_connect_tcp_connect(req);
119 34 : if (!tevent_req_is_in_progress(req)) {
120 0 : return tevent_req_post(req, ev);
121 : }
122 :
123 34 : return req;
124 : }
125 :
126 0 : static void http_connect_dns_done(struct tevent_req *subreq)
127 : {
128 0 : struct tevent_req *req = tevent_req_callback_data(
129 : subreq, struct tevent_req);
130 0 : struct http_connect_state *state = tevent_req_data(
131 : req, struct http_connect_state);
132 0 : struct dns_name_packet *dns_reply = NULL;
133 0 : struct dns_res_rec *an = NULL;
134 0 : uint16_t i;
135 0 : int ret;
136 :
137 0 : ret = dns_lookup_recv(subreq, state, &dns_reply);
138 0 : TALLOC_FREE(subreq);
139 0 : if (ret != 0) {
140 0 : tevent_req_error(req, ret);
141 0 : return;
142 : }
143 :
144 0 : for (i = 0; i < dns_reply->ancount; i++) {
145 0 : an = &dns_reply->answers[i];
146 0 : if (an->rr_type == DNS_QTYPE_A) {
147 0 : break;
148 : }
149 : }
150 0 : if (i >= dns_reply->ancount) {
151 0 : tevent_req_error(req, ENOENT);
152 0 : return;
153 : }
154 :
155 0 : state->http_server_ip = talloc_strdup(state, an->rdata.ipv4_record);
156 0 : if (tevent_req_nomem(state->http_server_ip, req)) {
157 0 : return;
158 : }
159 0 : http_connect_tcp_connect(req);
160 : }
161 :
162 34 : static void http_connect_tcp_connect(struct tevent_req *req)
163 : {
164 34 : struct http_connect_state *state = tevent_req_data(
165 : req, struct http_connect_state);
166 34 : struct tevent_req *subreq = NULL;
167 0 : int ret;
168 :
169 34 : ret = tsocket_address_inet_from_strings(state,
170 : "ip",
171 : state->http_server_ip,
172 : state->http_port,
173 : &state->remote_address);
174 34 : if (ret != 0) {
175 0 : int saved_errno = errno;
176 :
177 0 : DBG_ERR("Cannot create remote socket address, error: %s (%d)\n",
178 : strerror(errno), errno);
179 0 : tevent_req_error(req, saved_errno);
180 0 : return;
181 : }
182 :
183 34 : subreq = tstream_inet_tcp_connect_send(state,
184 : state->ev,
185 34 : state->local_address,
186 34 : state->remote_address);
187 34 : if (tevent_req_nomem(subreq, req)) {
188 0 : return;
189 : }
190 34 : tevent_req_set_callback(subreq, http_connect_tcp_done, req);
191 : }
192 :
193 34 : static void http_connect_tcp_done(struct tevent_req *subreq)
194 : {
195 34 : struct tevent_req *req = tevent_req_callback_data(
196 : subreq, struct tevent_req);
197 34 : struct http_connect_state *state = tevent_req_data(
198 : req, struct http_connect_state);
199 0 : int error;
200 0 : int ret;
201 :
202 34 : ret = tstream_inet_tcp_connect_recv(subreq,
203 : &error,
204 : state->http_conn,
205 : &state->http_conn->tstreams.raw,
206 : NULL);
207 34 : TALLOC_FREE(subreq);
208 34 : if (ret != 0) {
209 10 : tevent_req_error(req, error);
210 34 : return;
211 : }
212 :
213 24 : state->http_conn->tstreams.active = state->http_conn->tstreams.raw;
214 24 : DBG_DEBUG("Socket connected\n");
215 :
216 24 : if (state->tls_params == NULL) {
217 24 : tevent_req_done(req);
218 24 : return;
219 : }
220 :
221 0 : DBG_DEBUG("Starting TLS\n");
222 :
223 0 : subreq = tstream_tls_connect_send(state,
224 : state->ev,
225 : state->http_conn->tstreams.active,
226 : state->tls_params);
227 0 : if (tevent_req_nomem(subreq, req)) {
228 0 : return;
229 : }
230 0 : tevent_req_set_callback(subreq, http_connect_tls_done, req);
231 : }
232 :
233 0 : static void http_connect_tls_done(struct tevent_req *subreq)
234 : {
235 0 : struct tevent_req *req = tevent_req_callback_data(
236 : subreq, struct tevent_req);
237 0 : struct http_connect_state *state = tevent_req_data(
238 : req, struct http_connect_state);
239 0 : int error;
240 0 : int ret;
241 :
242 0 : ret = tstream_tls_connect_recv(subreq,
243 : &error,
244 0 : state->http_conn,
245 0 : &state->http_conn->tstreams.tls);
246 0 : TALLOC_FREE(subreq);
247 0 : if (ret != 0) {
248 0 : tevent_req_error(req, error);
249 0 : return;
250 : }
251 :
252 0 : state->http_conn->tstreams.active = state->http_conn->tstreams.tls;
253 :
254 0 : DBG_DEBUG("TLS handshake completed\n");
255 0 : tevent_req_done(req);
256 : }
257 :
258 34 : int http_connect_recv(struct tevent_req *req,
259 : TALLOC_CTX *mem_ctx,
260 : struct http_conn **http_conn)
261 : {
262 34 : struct http_connect_state *state = tevent_req_data(
263 : req, struct http_connect_state);
264 0 : int error;
265 :
266 34 : if (tevent_req_is_unix_error(req, &error)) {
267 10 : tevent_req_received(req);
268 10 : return error;
269 : }
270 :
271 24 : *http_conn = talloc_move(mem_ctx, &state->http_conn);
272 24 : tevent_req_received(req);
273 :
274 24 : return 0;
275 : }
276 :
277 0 : struct tevent_queue *http_conn_send_queue(struct http_conn *http_conn)
278 : {
279 0 : return http_conn->send_queue;
280 : }
281 :
282 0 : struct tstream_context *http_conn_tstream(struct http_conn *http_conn)
283 : {
284 0 : return http_conn->tstreams.active;
285 : }
286 :
287 : struct http_conn_disconnect_state {
288 : struct tevent_context *ev;
289 : struct http_conn *http_conn;
290 : };
291 :
292 : static void http_conn_disconnect_done(struct tevent_req *subreq);
293 :
294 0 : struct tevent_req *http_disconnect_send(TALLOC_CTX *mem_ctx,
295 : struct tevent_context *ev,
296 : struct http_conn *http_conn)
297 : {
298 0 : struct tevent_req *req = NULL;
299 0 : struct tevent_req *subreq = NULL;
300 0 : struct http_conn_disconnect_state *state = NULL;
301 :
302 0 : req = tevent_req_create(mem_ctx, &state,
303 : struct http_conn_disconnect_state);
304 0 : if (req == NULL) {
305 0 : return NULL;
306 : }
307 :
308 0 : *state = (struct http_conn_disconnect_state) {
309 : .ev = ev,
310 : .http_conn = http_conn,
311 : };
312 :
313 0 : if (http_conn->tstreams.active == NULL) {
314 0 : tevent_req_error(req, ENOTCONN);
315 0 : return tevent_req_post(req, ev);
316 : }
317 :
318 0 : subreq = tstream_disconnect_send(state, ev, http_conn->tstreams.active);
319 0 : if (tevent_req_nomem(subreq, req)) {
320 0 : return tevent_req_post(req, ev);
321 : }
322 0 : tevent_req_set_callback(subreq, http_conn_disconnect_done, req);
323 :
324 0 : return req;
325 : }
326 :
327 0 : static void http_conn_disconnect_done(struct tevent_req *subreq)
328 : {
329 0 : struct tevent_req *req = tevent_req_callback_data(
330 : subreq, struct tevent_req);
331 0 : int ret;
332 0 : int error;
333 :
334 0 : ret = tstream_disconnect_recv(subreq, &error);
335 0 : TALLOC_FREE(subreq);
336 0 : if (ret == -1) {
337 0 : tevent_req_error(req, error);
338 0 : return;
339 : }
340 :
341 0 : tevent_req_done(req);
342 : }
343 :
344 0 : int http_disconnect_recv(struct tevent_req *req)
345 : {
346 0 : return tevent_req_simple_recv_unix(req);
347 : }
|