mirror of
https://github.com/samba-team/samba.git
synced 2024-12-23 17:34:34 +03:00
ca93631291
Signed-off-by: Stefan Metzmacher <metze@samba.org> Reviewed-by: Andrew Bartlett <abartlet@samba.org>
406 lines
9.0 KiB
C
406 lines
9.0 KiB
C
#include "includes.h"
|
|
#include "version.h"
|
|
#include "libcli/libcli.h"
|
|
#include "lib/events/events.h"
|
|
#include "libcli/resolve/resolve.h"
|
|
#include "param/param.h"
|
|
#include "libcli/raw/raw_proto.h"
|
|
#include "libcli/http/http.h"
|
|
#include "credentials.h"
|
|
#include "util/tevent_ntstatus.h"
|
|
#include "lib/tls/tls.h"
|
|
#include "lib/cmdline/cmdline.h"
|
|
|
|
|
|
struct http_client_info {
|
|
struct http_conn *http_conn;
|
|
uint16_t server_port;
|
|
const char *server_addr;
|
|
struct tstream_tls_params *tls_params;
|
|
struct cli_credentials *creds;
|
|
struct loadparm_context *lp_ctx;
|
|
const char *uri;
|
|
};
|
|
|
|
static bool send_http_request(TALLOC_CTX *mem_ctx,
|
|
struct tevent_context *ev_ctx,
|
|
struct http_client_info* es,
|
|
size_t response_size,
|
|
NTSTATUS *pstatus)
|
|
{
|
|
struct http_request *http_req = NULL;
|
|
struct tevent_req *req = NULL;
|
|
char *uri = NULL;
|
|
struct http_request *http_response = NULL;
|
|
NTSTATUS status;
|
|
|
|
http_req = talloc_zero(mem_ctx, struct http_request);
|
|
if (!http_req) {
|
|
DBG_ERR("no memory\n");
|
|
return false;
|
|
}
|
|
|
|
uri = talloc_strdup(mem_ctx, es->uri);
|
|
|
|
http_req->type = HTTP_REQ_POST;
|
|
http_req->uri = uri;
|
|
http_req->body = data_blob_null;
|
|
http_req->major = '1';
|
|
http_req->minor = '1';
|
|
|
|
http_add_header(mem_ctx, &http_req->headers,
|
|
"User-Agent", "Samba/http_test");
|
|
http_add_header(mem_ctx, &http_req->headers,
|
|
"Accept", "*/*");
|
|
|
|
req = http_send_auth_request_send(mem_ctx,
|
|
ev_ctx,
|
|
es->http_conn,
|
|
http_req,
|
|
es->creds,
|
|
es->lp_ctx,
|
|
HTTP_AUTH_BASIC);
|
|
if (!tevent_req_set_endtime(req, ev_ctx, timeval_current_ofs(10, 0))) {
|
|
DBG_ERR("Failed to set timeout\n");
|
|
return false;
|
|
}
|
|
|
|
if (!tevent_req_poll_ntstatus(req, ev_ctx, pstatus)) {
|
|
DBG_ERR("Failed to connect: %s\n", nt_errstr(*pstatus));
|
|
return false;
|
|
}
|
|
|
|
status = http_send_auth_request_recv(req);
|
|
if (!NT_STATUS_IS_OK(status)) {
|
|
DBG_ERR("Auth request failed: %s\n", nt_errstr(status));
|
|
return false;
|
|
}
|
|
|
|
req = http_read_response_send(mem_ctx,
|
|
ev_ctx,
|
|
es->http_conn,
|
|
response_size);
|
|
if (!req) {
|
|
DBG_ERR("no memory\n");
|
|
return -1;
|
|
}
|
|
|
|
if (!tevent_req_set_endtime(req, ev_ctx, timeval_current_ofs(10, 0))) {
|
|
DBG_ERR("Failed to set timeout\n");
|
|
return false;
|
|
}
|
|
|
|
if (!tevent_req_poll_ntstatus(req, ev_ctx, pstatus)) {
|
|
DBG_ERR("Failed to read_resonse: %s\n", nt_errstr(*pstatus));
|
|
return false;
|
|
}
|
|
|
|
*pstatus = http_read_response_recv(req, mem_ctx, &http_response);
|
|
|
|
if (!NT_STATUS_IS_OK(*pstatus)) {
|
|
DBG_ERR("Failed to receive response: %s\n", nt_errstr(*pstatus));
|
|
return false;
|
|
}
|
|
/* following are not 'hard' errors */
|
|
if (http_response->response_code != 200) {
|
|
fprintf(stdout, "HTTP server response: %u\n",
|
|
http_response->response_code);
|
|
fflush(stdout);
|
|
return false;
|
|
|
|
}
|
|
if (http_response->body.length == 0) {
|
|
fprintf(stdout, "unexpected 0 len response\n");
|
|
fflush(stdout);
|
|
return false;
|
|
}
|
|
DBG_ERR("response: len (%d)\n%s\n",
|
|
(int)http_response->body.length,
|
|
talloc_strndup(mem_ctx,
|
|
(char *)http_response->body.data,
|
|
http_response->body.length));
|
|
fprintf(stdout,"%s", talloc_strndup(mem_ctx,
|
|
(char *)http_response->body.data,
|
|
http_response->body.length));
|
|
fflush(stdout);
|
|
return true;
|
|
}
|
|
|
|
int main(int argc, const char *argv[])
|
|
|
|
{
|
|
TALLOC_CTX *mem_ctx;
|
|
struct tevent_context *ev_ctx;
|
|
int retries = 4;
|
|
int count = 0;
|
|
struct http_client_info *http_info = NULL;
|
|
bool use_tls = false;
|
|
int res;
|
|
NTSTATUS status;
|
|
struct tevent_req *req = NULL;
|
|
bool connected = false;
|
|
poptContext pc;
|
|
const char **const_argv = discard_const_p(const char *, argv);
|
|
int opt;
|
|
bool ok;
|
|
const char *ca_file = NULL;
|
|
int port = 0;
|
|
size_t response_size = 8192000;
|
|
struct cli_credentials *cli_creds;
|
|
|
|
struct poptOption long_options[] = {
|
|
POPT_AUTOHELP
|
|
|
|
{
|
|
.longName = "usetls",
|
|
.shortName = 't',
|
|
.argInfo = POPT_ARG_NONE,
|
|
.arg = NULL,
|
|
.val = 't',
|
|
.descrip = "Use tls",
|
|
.argDescrip = "enable tls",
|
|
},
|
|
{
|
|
.longName = "ip-address",
|
|
.shortName = 'I',
|
|
.argInfo = POPT_ARG_STRING,
|
|
.arg = NULL,
|
|
.val = 'I',
|
|
.descrip = "Use this IP to connect to",
|
|
.argDescrip = "IP",
|
|
},
|
|
{
|
|
.longName = "port",
|
|
.shortName = 'p',
|
|
.argInfo = POPT_ARG_INT,
|
|
.arg = &port,
|
|
.val = 'p',
|
|
.descrip = "port to connect to",
|
|
.argDescrip = "port",
|
|
},
|
|
{
|
|
.longName = "cacart",
|
|
.shortName = 'c',
|
|
.argInfo = POPT_ARG_STRING,
|
|
.arg = NULL,
|
|
.val = 'c',
|
|
.descrip = "CA certificate to verify peer against",
|
|
.argDescrip = "ca cert",
|
|
},
|
|
{
|
|
.longName = "uri",
|
|
.shortName = 'u',
|
|
.argInfo = POPT_ARG_STRING,
|
|
.arg = NULL,
|
|
.val = 'u',
|
|
.descrip = "uri to send as part of http request",
|
|
.argDescrip = "uri",
|
|
},
|
|
{
|
|
.longName = "rsize",
|
|
.argInfo = POPT_ARG_LONG,
|
|
.arg = &response_size,
|
|
.descrip = "response size",
|
|
},
|
|
POPT_COMMON_SAMBA
|
|
POPT_COMMON_CREDENTIALS
|
|
POPT_TABLEEND
|
|
};
|
|
|
|
mem_ctx = talloc_init("http_test");
|
|
|
|
if (!mem_ctx) {
|
|
DBG_ERR("Not enough memory\n");
|
|
res = -1;
|
|
goto done;
|
|
}
|
|
|
|
http_info = talloc_zero(mem_ctx, struct http_client_info);
|
|
|
|
if (http_info == NULL) {
|
|
DBG_ERR("Not enough memory\n");
|
|
res = -1;
|
|
goto done;
|
|
}
|
|
|
|
ok = samba_cmdline_init(mem_ctx,
|
|
SAMBA_CMDLINE_CONFIG_CLIENT,
|
|
false /* require_smbconf */);
|
|
if (!ok) {
|
|
DBG_ERR("Failed to init cmdline parser!\n");
|
|
res = -1;
|
|
goto done;
|
|
}
|
|
|
|
pc = samba_popt_get_context(getprogname(),
|
|
argc,
|
|
const_argv,
|
|
long_options,
|
|
0);
|
|
if (pc == NULL) {
|
|
DBG_ERR("Failed to setup popt context!\n");
|
|
res = -1;
|
|
goto done;
|
|
}
|
|
|
|
/* some defaults */
|
|
|
|
http_info->server_addr = "localhost";
|
|
http_info->uri = "/_search?pretty";
|
|
|
|
while ((opt = poptGetNextOpt(pc)) != -1) {
|
|
switch (opt) {
|
|
case 't':
|
|
use_tls = true;
|
|
break;
|
|
case 'c': {
|
|
ca_file = talloc_strdup(mem_ctx,
|
|
poptGetOptArg(pc));
|
|
if (ca_file == NULL) {
|
|
DBG_ERR("Not enough memory\n");
|
|
res = -1;
|
|
goto done;
|
|
}
|
|
break;
|
|
}
|
|
case 'I': {
|
|
http_info->server_addr = talloc_strdup(mem_ctx,
|
|
poptGetOptArg(pc));
|
|
if (http_info->server_addr == NULL) {
|
|
DBG_ERR("Not enough memory\n");
|
|
res = -1;
|
|
goto done;
|
|
}
|
|
break;
|
|
}
|
|
case 'u': {
|
|
http_info->uri = talloc_strdup(mem_ctx,
|
|
poptGetOptArg(pc));
|
|
if (http_info->uri == NULL) {
|
|
DBG_ERR("Not enough memory\n");
|
|
res = -1;
|
|
goto done;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (use_tls && ca_file == NULL) {
|
|
DBG_ERR("No cacert\n");
|
|
res = -1;
|
|
poptPrintUsage(pc, stderr, 0);
|
|
goto done;
|
|
}
|
|
|
|
if (!port) {
|
|
port = 8080;
|
|
}
|
|
http_info->server_port = port;
|
|
|
|
ev_ctx = s4_event_context_init(mem_ctx);
|
|
if (!ev_ctx) {
|
|
DBG_ERR("Not enough memory\n");
|
|
res = -1;
|
|
goto done;
|
|
}
|
|
|
|
|
|
cli_creds = samba_cmdline_get_creds();
|
|
if (!cli_credentials_is_anonymous(cli_creds)) {
|
|
http_info->creds = cli_credentials_init(mem_ctx);
|
|
cli_credentials_set_username(
|
|
http_info->creds,
|
|
cli_credentials_get_username(cli_creds),
|
|
CRED_SPECIFIED);
|
|
cli_credentials_set_password(http_info->creds,
|
|
cli_credentials_get_password(cli_creds),
|
|
CRED_SPECIFIED);
|
|
} else {
|
|
DBG_DEBUG("Anonymous creds!!!\n");
|
|
http_info->creds = cli_creds;
|
|
}
|
|
if (http_info->creds == NULL) {
|
|
DBG_ERR("Failed to create creds\n");
|
|
res = -1;
|
|
goto done;
|
|
}
|
|
http_info->lp_ctx = samba_cmdline_get_lp_ctx();
|
|
|
|
DBG_ERR("retries = %d/%d, Using server %s, port %d, using tls %s\n",
|
|
count, retries,
|
|
http_info->server_addr,
|
|
http_info->server_port,
|
|
use_tls ? "true" : "false");
|
|
|
|
while (count < retries) {
|
|
int error;
|
|
DBG_ERR("Connecting to HTTP [%s] port [%"PRIu16"]%s\n",
|
|
http_info->server_addr, http_info->server_port,
|
|
use_tls ? " with tls" : " without tls");
|
|
if (use_tls) {
|
|
bool system_cas = false;
|
|
const char * const *ca_dirs = NULL;
|
|
const char *crl_file = NULL;
|
|
const char *tls_priority = "NORMAL:-VERS-SSL3.0";
|
|
enum tls_verify_peer_state verify_peer =
|
|
TLS_VERIFY_PEER_CA_ONLY;
|
|
|
|
status = tstream_tls_params_client(mem_ctx,
|
|
system_cas,
|
|
ca_dirs,
|
|
ca_file,
|
|
crl_file,
|
|
tls_priority,
|
|
verify_peer,
|
|
http_info->server_addr,
|
|
&http_info->tls_params);
|
|
if (!NT_STATUS_IS_OK(status)) {
|
|
DBG_ERR("Failed tstream_tls_params_client - %s\n",
|
|
nt_errstr(status));
|
|
res = -1;
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
req = http_connect_send(mem_ctx,
|
|
ev_ctx,
|
|
http_info->server_addr,
|
|
http_info->server_port,
|
|
http_info->creds,
|
|
http_info->tls_params);
|
|
if (!tevent_req_poll_ntstatus(req, ev_ctx, &status)) {
|
|
res = -1;
|
|
goto done;
|
|
}
|
|
|
|
error = http_connect_recv(req,
|
|
mem_ctx,
|
|
&http_info->http_conn);
|
|
if (error != 0) {
|
|
count++;
|
|
DBG_ERR("HTTP connection failed retry %d/%d: %s\n", count, retries, strerror(error));
|
|
} else {
|
|
DBG_ERR("HTTP connection succeeded\n");
|
|
connected = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!connected) {
|
|
DBG_ERR("Leaving early\n");
|
|
res = -1;
|
|
goto done;
|
|
}
|
|
|
|
if (!send_http_request(mem_ctx, ev_ctx, http_info, response_size, &status)) {
|
|
DBG_ERR("Failure\n");
|
|
res = -1;
|
|
goto done;
|
|
}
|
|
res = 0;
|
|
done:
|
|
TALLOC_FREE(mem_ctx);
|
|
return res;
|
|
}
|