2024-03-25 22:21:54 +03:00
# 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 ) {
2024-02-09 13:31:30 +03:00
bool system_cas = false ;
const char * const * ca_dirs = NULL ;
2024-03-25 22:21:54 +03:00
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 ,
2024-02-09 13:31:30 +03:00
system_cas ,
ca_dirs ,
2024-03-25 22:21:54 +03:00
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 ;
}