LCOV - code coverage report
Current view: top level - libcli/http - http_conn.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 52 149 34.9 %
Date: 2024-04-21 15:09:00 Functions: 4 11 36.4 %

          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             : }

Generated by: LCOV version 1.14