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