LCOV - code coverage report
Current view: top level - source4/client - http_test.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 108 183 59.0 %
Date: 2024-04-21 15:09:00 Functions: 2 2 100.0 %

          Line data    Source code
       1             : #include "includes.h"
       2             : #include "version.h"
       3             : #include "libcli/libcli.h"
       4             : #include "lib/events/events.h"
       5             : #include "libcli/resolve/resolve.h"
       6             : #include "param/param.h"
       7             : #include "libcli/raw/raw_proto.h"
       8             : #include "libcli/http/http.h"
       9             : #include "credentials.h"
      10             : #include "util/tevent_ntstatus.h"
      11             : #include "lib/tls/tls.h"
      12             : #include "lib/cmdline/cmdline.h"
      13             : 
      14             : 
      15             : struct http_client_info {
      16             :         struct http_conn *http_conn;
      17             :         uint16_t server_port;
      18             :         const char *server_addr;
      19             :         struct tstream_tls_params *tls_params;
      20             :         struct cli_credentials *creds;
      21             :         struct loadparm_context *lp_ctx;
      22             :         const char *uri;
      23             : };
      24             : 
      25          14 : static bool send_http_request(TALLOC_CTX *mem_ctx,
      26             :         struct tevent_context *ev_ctx,
      27             :         struct http_client_info* es,
      28             :         size_t response_size,
      29             :         NTSTATUS *pstatus)
      30             : {
      31          14 :         struct http_request *http_req = NULL;
      32          14 :         struct tevent_req *req = NULL;
      33          14 :         char *uri = NULL;
      34          14 :         struct http_request *http_response = NULL;
      35             :         NTSTATUS status;
      36             : 
      37          14 :         http_req = talloc_zero(mem_ctx, struct http_request);
      38          14 :         if (!http_req) {
      39           0 :                 DBG_ERR("no memory\n");
      40           0 :                 return false;
      41             :         }
      42             : 
      43          14 :         uri = talloc_strdup(mem_ctx, es->uri);
      44             : 
      45          14 :         http_req->type = HTTP_REQ_POST;
      46          14 :         http_req->uri = uri;
      47          14 :         http_req->body = data_blob_null;
      48          14 :         http_req->major = '1';
      49          14 :         http_req->minor = '1';
      50             : 
      51          14 :         http_add_header(mem_ctx, &http_req->headers,
      52             :                         "User-Agent", "Samba/http_test");
      53          14 :         http_add_header(mem_ctx, &http_req->headers,
      54             :                         "Accept", "*/*");
      55             : 
      56          14 :         req = http_send_auth_request_send(mem_ctx,
      57             :                                 ev_ctx,
      58             :                                 es->http_conn,
      59             :                                 http_req,
      60             :                                 es->creds,
      61             :                                 es->lp_ctx,
      62             :                                 HTTP_AUTH_BASIC);
      63          14 :         if (!tevent_req_set_endtime(req, ev_ctx, timeval_current_ofs(10, 0))) {
      64           0 :                 DBG_ERR("Failed to set timeout\n");
      65           0 :                 return false;
      66             :         }
      67             : 
      68          14 :         if (!tevent_req_poll_ntstatus(req, ev_ctx, pstatus)) {
      69           0 :                 DBG_ERR("Failed to connect: %s\n", nt_errstr(*pstatus));
      70           0 :                 return false;
      71             :         }
      72             : 
      73          14 :         status = http_send_auth_request_recv(req);
      74          14 :         if (!NT_STATUS_IS_OK(status)) {
      75           0 :                 DBG_ERR("Auth request failed: %s\n", nt_errstr(status));
      76           0 :                 return false;
      77             :         }
      78             : 
      79          14 :         req = http_read_response_send(mem_ctx,
      80             :                                 ev_ctx,
      81             :                                 es->http_conn,
      82             :                                 response_size);
      83          14 :         if (!req) {
      84           0 :                 DBG_ERR("no memory\n");
      85           0 :                 return -1;
      86             :         }
      87             : 
      88          14 :         if (!tevent_req_set_endtime(req, ev_ctx, timeval_current_ofs(10, 0))) {
      89           0 :                 DBG_ERR("Failed to set timeout\n");
      90           0 :                 return false;
      91             :         }
      92             : 
      93          14 :         if (!tevent_req_poll_ntstatus(req, ev_ctx, pstatus)) {
      94           0 :                 DBG_ERR("Failed to read_resonse: %s\n", nt_errstr(*pstatus));
      95           0 :                 return false;
      96             :         }
      97             : 
      98          14 :         *pstatus = http_read_response_recv(req, mem_ctx, &http_response);
      99             : 
     100          14 :         if (!NT_STATUS_IS_OK(*pstatus)) {
     101           2 :                 DBG_ERR("Failed to receive response: %s\n", nt_errstr(*pstatus));
     102           2 :                 return false;
     103             :         }
     104             :         /* following are not 'hard' errors */
     105          12 :         if (http_response->response_code != 200) {
     106           0 :                 fprintf(stdout, "HTTP server response: %u\n",
     107           0 :                         http_response->response_code);
     108           0 :                 fflush(stdout);
     109           0 :                 return false;
     110             : 
     111             :         }
     112          12 :         if (http_response->body.length == 0) {
     113           4 :                 fprintf(stdout, "unexpected 0 len response\n");
     114           4 :                 fflush(stdout);
     115           4 :                 return false;
     116             :         }
     117           8 :         DBG_ERR("response: len (%d)\n%s\n",
     118             :                   (int)http_response->body.length,
     119             :                   talloc_strndup(mem_ctx,
     120             :                                  (char *)http_response->body.data,
     121             :                                  http_response->body.length));
     122           8 :         fprintf(stdout,"%s", talloc_strndup(mem_ctx,
     123           8 :                                             (char *)http_response->body.data,
     124           8 :                                             http_response->body.length));
     125           8 :         fflush(stdout);
     126           8 :         return true;
     127             : }
     128             : 
     129          14 : int main(int argc, const char *argv[])
     130             : 
     131             : {
     132             :         TALLOC_CTX *mem_ctx;
     133             :         struct tevent_context *ev_ctx;
     134          14 :         int retries = 4;
     135          14 :         int count = 0;
     136          14 :         struct http_client_info *http_info = NULL;
     137          14 :         bool use_tls = false;
     138             :         int res;
     139             :         NTSTATUS status;
     140          14 :         struct tevent_req *req = NULL;
     141          14 :         bool connected = false;
     142             :         poptContext pc;
     143          14 :         const char **const_argv = discard_const_p(const char *, argv);
     144             :         int opt;
     145             :         bool ok;
     146          14 :         const char *ca_file = NULL;
     147          14 :         int port = 0;
     148          14 :         size_t response_size = 8192000;
     149             :         struct cli_credentials *cli_creds;
     150             : 
     151          42 :         struct poptOption long_options[] = {
     152             :                 POPT_AUTOHELP
     153             : 
     154             :                 {
     155             :                         .longName   = "usetls",
     156             :                         .shortName  = 't',
     157             :                         .argInfo    = POPT_ARG_NONE,
     158             :                         .arg        = NULL,
     159             :                         .val        = 't',
     160             :                         .descrip    = "Use tls",
     161             :                         .argDescrip = "enable tls",
     162             :                 },
     163             :                 {
     164             :                         .longName   = "ip-address",
     165             :                         .shortName  = 'I',
     166             :                         .argInfo    = POPT_ARG_STRING,
     167             :                         .arg        = NULL,
     168             :                         .val        = 'I',
     169             :                         .descrip    = "Use this IP to connect to",
     170             :                         .argDescrip = "IP",
     171             :                 },
     172             :                 {
     173             :                         .longName   = "port",
     174             :                         .shortName  = 'p',
     175             :                         .argInfo    = POPT_ARG_INT,
     176             :                         .arg        = &port,
     177             :                         .val        = 'p',
     178             :                         .descrip    = "port to connect to",
     179             :                         .argDescrip = "port",
     180             :                 },
     181             :                 {
     182             :                         .longName   = "cacart",
     183             :                         .shortName  = 'c',
     184             :                         .argInfo    = POPT_ARG_STRING,
     185             :                         .arg        = NULL,
     186             :                         .val        = 'c',
     187             :                         .descrip    = "CA certificate to verify peer against",
     188             :                         .argDescrip = "ca cert",
     189             :                 },
     190             :                 {
     191             :                         .longName   = "uri",
     192             :                         .shortName  = 'u',
     193             :                         .argInfo    = POPT_ARG_STRING,
     194             :                         .arg        = NULL,
     195             :                         .val        = 'u',
     196             :                         .descrip    = "uri to send as part of http request",
     197             :                         .argDescrip = "uri",
     198             :                 },
     199             :                 {
     200             :                         .longName   = "rsize",
     201             :                         .argInfo    = POPT_ARG_LONG,
     202             :                         .arg        = &response_size,
     203             :                         .descrip    = "response size",
     204             :                 },
     205          14 :                 POPT_COMMON_SAMBA
     206          14 :                 POPT_COMMON_CREDENTIALS
     207             :                 POPT_TABLEEND
     208             :         };
     209             : 
     210          14 :         mem_ctx = talloc_init("http_test");
     211             : 
     212          14 :         if (!mem_ctx) {
     213           0 :                 DBG_ERR("Not enough memory\n");
     214           0 :                 res = -1;
     215           0 :                 goto done;
     216             :         }
     217             : 
     218          14 :         http_info = talloc_zero(mem_ctx, struct http_client_info);
     219             : 
     220          14 :         if (http_info == NULL) {
     221           0 :                 DBG_ERR("Not enough memory\n");
     222           0 :                 res = -1;
     223           0 :                 goto done;
     224             :         }
     225             : 
     226          14 :         ok = samba_cmdline_init(mem_ctx,
     227             :                                 SAMBA_CMDLINE_CONFIG_CLIENT,
     228             :                                 false /* require_smbconf */);
     229          14 :         if (!ok) {
     230           0 :                 DBG_ERR("Failed to init cmdline parser!\n");
     231           0 :                 res = -1;
     232           0 :                 goto done;
     233             :         }
     234             : 
     235          14 :         pc = samba_popt_get_context(getprogname(),
     236             :                                     argc,
     237             :                                     const_argv,
     238             :                                     long_options,
     239             :                                     0);
     240          14 :         if (pc == NULL) {
     241           0 :                 DBG_ERR("Failed to setup popt context!\n");
     242           0 :                 res = -1;
     243           0 :                 goto done;
     244             :         }
     245             : 
     246             :         /* some defaults */
     247             : 
     248          14 :         http_info->server_addr = "localhost";
     249          14 :         http_info->uri = "/_search?pretty";
     250             : 
     251          42 :         while ((opt = poptGetNextOpt(pc)) != -1) {
     252          28 :                 switch (opt) {
     253           0 :                         case 't':
     254           0 :                                 use_tls = true;
     255           0 :                                 break;
     256           0 :                         case  'c': {
     257           0 :                                 ca_file = talloc_strdup(mem_ctx,
     258           0 :                                                         poptGetOptArg(pc));
     259           0 :                                 if (ca_file == NULL) {
     260           0 :                                         DBG_ERR("Not enough memory\n");
     261           0 :                                         res = -1;
     262           0 :                                         goto done;
     263             :                                 }
     264           0 :                                 break;
     265             :                         }
     266          14 :                         case 'I': {
     267          14 :                                 http_info->server_addr = talloc_strdup(mem_ctx,
     268          14 :                                                         poptGetOptArg(pc));
     269          14 :                                 if (http_info->server_addr == NULL) {
     270           0 :                                         DBG_ERR("Not enough memory\n");
     271           0 :                                         res = -1;
     272           0 :                                         goto done;
     273             :                                 }
     274          14 :                                 break;
     275             :                         }
     276          14 :                         case 'u': {
     277          14 :                                 http_info->uri = talloc_strdup(mem_ctx,
     278          14 :                                                         poptGetOptArg(pc));
     279          14 :                                 if (http_info->uri == NULL) {
     280           0 :                                         DBG_ERR("Not enough memory\n");
     281           0 :                                         res = -1;
     282           0 :                                         goto done;
     283             :                                 }
     284          14 :                                 break;
     285             :                         }
     286             :                 }
     287             :         }
     288             : 
     289          14 :         if (use_tls && ca_file == NULL) {
     290           0 :                 DBG_ERR("No cacert\n");
     291           0 :                 res = -1;
     292           0 :                 poptPrintUsage(pc, stderr, 0);
     293           0 :                 goto done;
     294             :         }
     295             : 
     296          14 :         if (!port) {
     297          14 :                 port = 8080;
     298             :         }
     299          14 :         http_info->server_port = port;
     300             : 
     301          14 :         ev_ctx = s4_event_context_init(mem_ctx);
     302          14 :         if (!ev_ctx) {
     303           0 :                 DBG_ERR("Not enough memory\n");
     304           0 :                 res = -1;
     305           0 :                 goto done;
     306             :         }
     307             : 
     308             : 
     309          14 :         cli_creds = samba_cmdline_get_creds();
     310          14 :         if (!cli_credentials_is_anonymous(cli_creds)) {
     311           0 :                 http_info->creds = cli_credentials_init(mem_ctx);
     312           0 :                 cli_credentials_set_username(
     313             :                         http_info->creds,
     314             :                         cli_credentials_get_username(cli_creds),
     315             :                         CRED_SPECIFIED);
     316           0 :                 cli_credentials_set_password(http_info->creds,
     317             :                         cli_credentials_get_password(cli_creds),
     318             :                         CRED_SPECIFIED);
     319             :         } else {
     320          14 :                 DBG_DEBUG("Anonymous creds!!!\n");
     321          14 :                 http_info->creds = cli_creds;
     322             :         }
     323          14 :         if (http_info->creds == NULL) {
     324           0 :                 DBG_ERR("Failed to create creds\n");
     325           0 :                 res = -1;
     326           0 :                 goto done;
     327             :         }
     328          14 :         http_info->lp_ctx = samba_cmdline_get_lp_ctx();
     329             : 
     330          14 :         DBG_ERR("retries = %d/%d, Using server %s, port %d, using tls %s\n",
     331             :                 count, retries,
     332             :                 http_info->server_addr,
     333             :                 http_info->server_port,
     334             :                 use_tls ? "true" : "false");
     335             : 
     336          14 :         while (count < retries) {
     337             :                 int error;
     338          14 :                 DBG_ERR("Connecting to HTTP [%s] port [%"PRIu16"]%s\n",
     339             :                         http_info->server_addr, http_info->server_port,
     340             :                         use_tls ? " with tls" : " without tls");
     341          14 :                 if (use_tls) {
     342           0 :                         const char *crl_file = NULL;
     343           0 :                         const char *tls_priority = "NORMAL:-VERS-SSL3.0";
     344           0 :                         enum tls_verify_peer_state verify_peer =
     345             :                                 TLS_VERIFY_PEER_CA_ONLY;
     346             : 
     347           0 :                         status = tstream_tls_params_client(mem_ctx,
     348             :                                                    ca_file,
     349             :                                                    crl_file,
     350             :                                                    tls_priority,
     351             :                                                    verify_peer,
     352             :                                                    http_info->server_addr,
     353             :                                                    &http_info->tls_params);
     354           0 :                         if (!NT_STATUS_IS_OK(status)) {
     355           0 :                                 DBG_ERR("Failed tstream_tls_params_client - %s\n",
     356             :                                         nt_errstr(status));
     357           0 :                                 res = -1;
     358           0 :                                 goto done;
     359             :                         }
     360             :                 }
     361             : 
     362          14 :                 req = http_connect_send(mem_ctx,
     363             :                                         ev_ctx,
     364             :                                         http_info->server_addr,
     365          14 :                                         http_info->server_port,
     366             :                                         http_info->creds,
     367             :                                         http_info->tls_params);
     368          14 :                 if (!tevent_req_poll_ntstatus(req, ev_ctx, &status)) {
     369           0 :                         res = -1;
     370           0 :                         goto done;
     371             :                 }
     372             : 
     373          14 :                 error = http_connect_recv(req,
     374             :                                         mem_ctx,
     375             :                                         &http_info->http_conn);
     376          14 :                 if (error != 0) {
     377           0 :                         count++;
     378           0 :                         DBG_ERR("HTTP connection failed retry %d/%d: %s\n", count, retries, strerror(error));
     379             :                 } else {
     380          14 :                         DBG_ERR("HTTP connection succeeded\n");
     381          14 :                         connected = true;
     382          14 :                         break;
     383             :                 }
     384             :         }
     385             : 
     386          14 :         if (!connected) {
     387           0 :                 DBG_ERR("Leaving early\n");
     388           0 :                 res = -1;
     389           0 :                 goto done;
     390             :         }
     391             : 
     392          14 :         if (!send_http_request(mem_ctx, ev_ctx, http_info, response_size, &status)) {
     393           6 :                 DBG_ERR("Failure\n");
     394           6 :                 res = -1;
     395           6 :                 goto done;
     396             :         }
     397           8 :         res = 0;
     398          14 : done:
     399          14 :         TALLOC_FREE(mem_ctx);
     400          14 :         return res;
     401             : }

Generated by: LCOV version 1.14