s3: smbd: Deliberately currupt an uninitialized pointer.
[Samba.git] / libcli / http / http_conn.c
blobac39a0a58d899a287b65c66aadbb711eac08e38e
1 /*
2 Unix SMB/CIFS implementation.
4 HTTP library
6 Copyright (C) 2019 Ralph Boehme <slow@samba.org>
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.
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.
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/>.
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"
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;
42 struct http_conn *http_conn;
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);
50 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)
57 struct tevent_req *req = NULL;
58 struct tevent_req *subreq = NULL;
59 struct http_connect_state *state = NULL;
60 int ret;
62 DBG_DEBUG("Connecting to [%s] over HTTP%s\n",
63 http_server, tls_params != NULL ? "S" : "");
65 req = tevent_req_create(mem_ctx, &state, struct http_connect_state);
66 if (req == NULL) {
67 return NULL;
70 *state = (struct http_connect_state) {
71 .ev = ev,
72 .http_port = http_port,
73 .credentials = credentials,
74 .tls_params = tls_params,
77 state->http_server = talloc_strdup(state, http_server);
78 if (tevent_req_nomem(state->http_server, req)) {
79 return tevent_req_post(req, ev);
82 state->http_conn = talloc_zero(state, struct http_conn);
83 if (tevent_req_nomem(state->http_conn, req)) {
84 return tevent_req_post(req, ev);
87 state->http_conn->send_queue = tevent_queue_create(state->http_conn,
88 "HTTP send queue");
89 if (tevent_req_nomem(state->http_conn->send_queue, req)) {
90 return tevent_req_post(req, ev);
93 ret = tsocket_address_inet_from_strings(state,
94 "ip",
95 NULL,
97 &state->local_address);
98 if (ret != 0) {
99 tevent_req_error(req, errno);
100 return tevent_req_post(req, ev);
103 if (!is_ipaddress(http_server)) {
104 subreq = dns_lookup_send(state,
106 NULL,
107 http_server,
108 DNS_QCLASS_IN,
109 DNS_QTYPE_A);
110 if (tevent_req_nomem(subreq, req)) {
111 return tevent_req_post(req, ev);
113 tevent_req_set_callback(subreq, http_connect_dns_done, req);
114 return req;
116 state->http_server_ip = state->http_server;
118 http_connect_tcp_connect(req);
119 if (!tevent_req_is_in_progress(req)) {
120 return tevent_req_post(req, ev);
123 return req;
126 static void http_connect_dns_done(struct tevent_req *subreq)
128 struct tevent_req *req = tevent_req_callback_data(
129 subreq, struct tevent_req);
130 struct http_connect_state *state = tevent_req_data(
131 req, struct http_connect_state);
132 struct dns_name_packet *dns_reply = NULL;
133 struct dns_res_rec *an = NULL;
134 uint16_t i;
135 int ret;
137 ret = dns_lookup_recv(subreq, state, &dns_reply);
138 TALLOC_FREE(subreq);
139 if (ret != 0) {
140 tevent_req_error(req, ret);
141 return;
144 for (i = 0; i < dns_reply->ancount; i++) {
145 an = &dns_reply->answers[i];
146 if (an->rr_type == DNS_QTYPE_A) {
147 break;
150 if (i >= dns_reply->ancount) {
151 tevent_req_error(req, ENOENT);
152 return;
155 state->http_server_ip = talloc_strdup(state, an->rdata.ipv4_record);
156 if (tevent_req_nomem(state->http_server_ip, req)) {
157 return;
159 http_connect_tcp_connect(req);
162 static void http_connect_tcp_connect(struct tevent_req *req)
164 struct http_connect_state *state = tevent_req_data(
165 req, struct http_connect_state);
166 struct tevent_req *subreq = NULL;
167 int ret;
169 ret = tsocket_address_inet_from_strings(state,
170 "ip",
171 state->http_server_ip,
172 state->http_port,
173 &state->remote_address);
174 if (ret != 0) {
175 int saved_errno = errno;
177 DBG_ERR("Cannot create remote socket address, error: %s (%d)\n",
178 strerror(errno), errno);
179 tevent_req_error(req, saved_errno);
180 return;
183 subreq = tstream_inet_tcp_connect_send(state,
184 state->ev,
185 state->local_address,
186 state->remote_address);
187 if (tevent_req_nomem(subreq, req)) {
188 return;
190 tevent_req_set_callback(subreq, http_connect_tcp_done, req);
193 static void http_connect_tcp_done(struct tevent_req *subreq)
195 struct tevent_req *req = tevent_req_callback_data(
196 subreq, struct tevent_req);
197 struct http_connect_state *state = tevent_req_data(
198 req, struct http_connect_state);
199 int error;
200 int ret;
202 ret = tstream_inet_tcp_connect_recv(subreq,
203 &error,
204 state->http_conn,
205 &state->http_conn->tstreams.raw,
206 NULL);
207 TALLOC_FREE(subreq);
208 if (ret != 0) {
209 tevent_req_error(req, error);
210 return;
213 state->http_conn->tstreams.active = state->http_conn->tstreams.raw;
214 DBG_DEBUG("Socket connected\n");
216 if (state->tls_params == NULL) {
217 tevent_req_done(req);
218 return;
221 DBG_DEBUG("Starting TLS\n");
223 subreq = tstream_tls_connect_send(state,
224 state->ev,
225 state->http_conn->tstreams.active,
226 state->tls_params);
227 if (tevent_req_nomem(subreq, req)) {
228 return;
230 tevent_req_set_callback(subreq, http_connect_tls_done, req);
233 static void http_connect_tls_done(struct tevent_req *subreq)
235 struct tevent_req *req = tevent_req_callback_data(
236 subreq, struct tevent_req);
237 struct http_connect_state *state = tevent_req_data(
238 req, struct http_connect_state);
239 int error;
240 int ret;
242 ret = tstream_tls_connect_recv(subreq,
243 &error,
244 state->http_conn,
245 &state->http_conn->tstreams.tls);
246 TALLOC_FREE(subreq);
247 if (ret != 0) {
248 tevent_req_error(req, error);
249 return;
252 state->http_conn->tstreams.active = state->http_conn->tstreams.tls;
254 DBG_DEBUG("TLS handshake completed\n");
255 tevent_req_done(req);
258 int http_connect_recv(struct tevent_req *req,
259 TALLOC_CTX *mem_ctx,
260 struct http_conn **http_conn)
262 struct http_connect_state *state = tevent_req_data(
263 req, struct http_connect_state);
264 int error;
266 if (tevent_req_is_unix_error(req, &error)) {
267 tevent_req_received(req);
268 return error;
271 *http_conn = talloc_move(mem_ctx, &state->http_conn);
272 tevent_req_received(req);
274 return 0;
277 struct tevent_queue *http_conn_send_queue(struct http_conn *http_conn)
279 return http_conn->send_queue;
282 struct tstream_context *http_conn_tstream(struct http_conn *http_conn)
284 return http_conn->tstreams.active;
287 struct http_conn_disconnect_state {
288 struct tevent_context *ev;
289 struct http_conn *http_conn;
292 static void http_conn_disconnect_done(struct tevent_req *subreq);
294 struct tevent_req *http_disconnect_send(TALLOC_CTX *mem_ctx,
295 struct tevent_context *ev,
296 struct http_conn *http_conn)
298 struct tevent_req *req = NULL;
299 struct tevent_req *subreq = NULL;
300 struct http_conn_disconnect_state *state = NULL;
302 req = tevent_req_create(mem_ctx, &state,
303 struct http_conn_disconnect_state);
304 if (req == NULL) {
305 return NULL;
308 *state = (struct http_conn_disconnect_state) {
309 .ev = ev,
310 .http_conn = http_conn,
313 if (http_conn->tstreams.active == NULL) {
314 tevent_req_error(req, ENOTCONN);
315 return tevent_req_post(req, ev);
318 subreq = tstream_disconnect_send(state, ev, http_conn->tstreams.active);
319 if (tevent_req_nomem(subreq, req)) {
320 return tevent_req_post(req, ev);
322 tevent_req_set_callback(subreq, http_conn_disconnect_done, req);
324 return req;
327 static void http_conn_disconnect_done(struct tevent_req *subreq)
329 struct tevent_req *req = tevent_req_callback_data(
330 subreq, struct tevent_req);
331 int ret;
332 int error;
334 ret = tstream_disconnect_recv(subreq, &error);
335 TALLOC_FREE(subreq);
336 if (ret == -1) {
337 tevent_req_error(req, error);
338 return;
341 tevent_req_done(req);
344 int http_disconnect_recv(struct tevent_req *req)
346 return tevent_req_simple_recv_unix(req);