>From 393eee0b156ca8cedf3021c443eb95b799eea3e5 Mon Sep 17 00:00:00 2001 From: Noel Power Date: Mon, 30 Jun 2014 16:08:04 +0100 Subject: [PATCH 2/5] reference 'raw smb pipe' test client and server the intention is client here will either be used directly for a torture test (via script) or it will be folded into the existing binary torture test framework (when I get to grips with it) --- librpc/idl/raw_np_echotest.idl | 31 ++++ librpc/idl/wscript_build | 2 +- librpc/wscript_build | 12 +- source3/rpc_server/rpc_service_setup.c | 25 +++ source3/rpc_server/wscript_build | 6 + source3/utils/rawpipeecho_testcli.c | 280 +++++++++++++++++++++++++++++++++ source3/wscript_build | 10 ++ 7 files changed, 364 insertions(+), 2 deletions(-) create mode 100644 librpc/idl/raw_np_echotest.idl create mode 100644 source3/utils/rawpipeecho_testcli.c diff --git a/librpc/idl/raw_np_echotest.idl b/librpc/idl/raw_np_echotest.idl new file mode 100644 index 0000000..fc1c29a --- /dev/null +++ b/librpc/idl/raw_np_echotest.idl @@ -0,0 +1,31 @@ +#include "idl_types.h" +import "misc.idl"; + +[ + uuid("BAD00000-DEAD-0000-0000-000000ABCDEF"), + version(1.0), + endpoint("ncacn_np:[\\pipe\\RawPipeEcho]"), + helpstring("Raw Pipe echo"), + pointer_default(unique ) +] + +interface rawpipeecho +{ + const uint32 TSTREAM_MAXDATA = 4280; + const uint32 ECHO_TEST = 0x00000001; + const uint32 ECHO_LARGE_MSG_TEST = 0x00000002; + + typedef [public] struct { + uint32 msg; + [flag(STR_NULLTERM)] string description; + uint32 nbytes; + uint8 payload[nbytes]; + + } raw_np_request; + + typedef [public] struct { + uint32 nbytes; + uint8 payload[nbytes]; + } raw_np_response; + +}; diff --git a/librpc/idl/wscript_build b/librpc/idl/wscript_build index 1bac9a7..969fe36 100644 --- a/librpc/idl/wscript_build +++ b/librpc/idl/wscript_build @@ -13,7 +13,7 @@ bld.SAMBA_PIDL_LIST('PIDL', notify.idl smb2_lease_struct.idl policyagent.idl scerpc.idl svcctl.idl wkssvc.idl eventlog6.idl backupkey.idl - fsrvp.idl witness.idl''', + fsrvp.idl witness.idl raw_np_echotest.idl''', options='--header --ndr-parser --samba3-ndr-server --server --client --python', output_dir='../gen_ndr') diff --git a/librpc/wscript_build b/librpc/wscript_build index da61a5a..0e870cd 100644 --- a/librpc/wscript_build +++ b/librpc/wscript_build @@ -335,6 +335,11 @@ bld.SAMBA_LIBRARY('ndr-krb5pac', vnum='0.0.1' ) +bld.SAMBA_SUBSYSTEM('NDR_RAW_NP_ECHOTEST', + source='gen_ndr/ndr_raw_np_echotest.c', + public_deps='ndr' + ) + bld.SAMBA_LIBRARY('ndr-standard', source='gen_ndr/ndr_eventlog6.c', vnum='0.0.1', @@ -620,6 +625,11 @@ bld.SAMBA_SUBSYSTEM('NDR_IOCTL', public_deps='ndr' ) +bld.SAMBA_SUBSYSTEM('RAW_NDR_RAW_NP_ECHOTEST', + source='gen_ndr/ndr_raw_np_echotest_c.c', + public_deps='dcerpc-binding NDR_RAW_NP_ECHOTEST' + ) + bld.SAMBA_SUBSYSTEM('RPC_NDR_FSRVP', source='gen_ndr/ndr_fsrvp_c.c', public_deps='dcerpc-binding NDR_FSRVP' @@ -635,7 +645,7 @@ bld.SAMBA_LIBRARY('ndr-samba', source=[], deps='''NDR_DRSBLOBS NDR_DRSUAPI NDR_IDMAP NDR_NTLMSSP NDR_SCHANNEL NDR_MGMT NDR_DNSP NDR_EPMAPPER NDR_XATTR NDR_UNIXINFO NDR_NAMED_PIPE_AUTH NDR_DCOM - NDR_NTPRINTING NDR_FSRVP NDR_WITNESS NDR_OPEN_FILES NDR_SMBXSRV''', + NDR_NTPRINTING NDR_FSRVP NDR_WITNESS NDR_OPEN_FILES NDR_SMBXSRV NDR_RAW_NP_ECHOTEST''', private_library=True, grouping_library=True ) diff --git a/source3/rpc_server/rpc_service_setup.c b/source3/rpc_server/rpc_service_setup.c index b8bb8ae..04f8458 100644 --- a/source3/rpc_server/rpc_service_setup.c +++ b/source3/rpc_server/rpc_service_setup.c @@ -38,6 +38,7 @@ #include "../librpc/gen_ndr/srv_spoolss.h" #include "../librpc/gen_ndr/srv_svcctl.h" #include "../librpc/gen_ndr/srv_wkssvc.h" +#include "../librpc/gen_ndr/srv_raw_np_echotest.h" #include "printing/nt_printing_migrate_internal.h" #include "rpc_server/eventlog/srv_eventlog_reg.h" @@ -112,6 +113,25 @@ static bool rpc_setup_winreg(struct tevent_context *ev_ctx, return rpc_setup_embedded(ev_ctx, msg_ctx, t, pipe_name); } +static bool rpc_setup_rawpipeecho(struct tevent_context *ev_ctx, + struct messaging_context *msg_ctx) +{ + const struct ndr_interface_table *t = &ndr_table_rawpipeecho; + const char *pipe_name = "raw_np_echotest"; + NTSTATUS status; + enum rpc_service_mode_e service_mode = rpc_service_mode(t->name); + if (service_mode != RPC_SERVICE_MODE_EMBEDDED) { + return true; + } + + status = rpc_rawpipeecho_init(NULL); + if (!NT_STATUS_IS_OK(status)) { + return false; + } + + return rpc_setup_embedded(ev_ctx, msg_ctx, t, pipe_name); +} + static bool rpc_setup_srvsvc(struct tevent_context *ev_ctx, struct messaging_context *msg_ctx) { @@ -454,6 +474,11 @@ bool dcesrv_ep_setup(struct tevent_context *ev_ctx, return false; } + ok = rpc_setup_rawpipeecho(ev_ctx, msg_ctx); + if (!ok) { + goto done; + } + ok = rpc_setup_winreg(ev_ctx, msg_ctx); if (!ok) { goto done; diff --git a/source3/rpc_server/wscript_build b/source3/rpc_server/wscript_build index 57d28cd..c09c200 100755 --- a/source3/rpc_server/wscript_build +++ b/source3/rpc_server/wscript_build @@ -125,6 +125,11 @@ bld.SAMBA3_SUBSYSTEM('RPC_WKSSVC', ../../librpc/gen_ndr/srv_wkssvc.c''', deps='LIBNET') +bld.SAMBA3_SUBSYSTEM('RPC_SRVRAW_NP_ECHOTEST', + source='''raw_np_echotest/raw_np_echotest_srv.c + ../../librpc/gen_ndr/srv_raw_np_echotest.c''', + deps='samba-util tdb') + # RPC_SERVICE bld.SAMBA3_SUBSYSTEM('RPC_SERVER_REGISTER', source='rpc_ep_register.c ../librpc/rpc/dcerpc_ep.c', @@ -151,6 +156,7 @@ bld.SAMBA3_SUBSYSTEM('RPC_SERVICE', RPC_RPCECHO RPC_SERVER RPC_EPMAPPER + RPC_SRVRAW_NP_ECHOTEST ''') # RPC_DAEMONS diff --git a/source3/utils/rawpipeecho_testcli.c b/source3/utils/rawpipeecho_testcli.c new file mode 100644 index 0000000..ef7c724 --- /dev/null +++ b/source3/utils/rawpipeecho_testcli.c @@ -0,0 +1,280 @@ +/* + Unix SMB/CIFS implementation. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "includes.h" +#include "popt_common.h" +#include "../libcli/security/security.h" +#include "libsmb/libsmb.h" +#include "libsmb/clirap.h" +#include "passdb/machine_sid.h" +#include "rpc_client/raw_pipe.h" +#include "bin/default/librpc/gen_ndr/ndr_raw_np_echotest.h" +#include "bin/default/librpc/gen_ndr/ndr_raw_np_echotest_c.h" +#include "raw_pipe_common.h" + +/***************************************************** + Return a connection to a server. +*******************************************************/ +static struct cli_state *connect_server(struct user_auth_info *auth_info, + const char *server) +{ + struct cli_state *c = NULL; + NTSTATUS nt_status; + uint32_t flags = 0; + + if (get_cmdline_auth_info_use_kerberos(auth_info)) { + flags |= CLI_FULL_CONNECTION_USE_KERBEROS | + CLI_FULL_CONNECTION_FALLBACK_AFTER_KERBEROS; + } + + if (get_cmdline_auth_info_use_machine_account(auth_info) && + !set_cmdline_auth_info_machine_account_creds(auth_info)) { + return NULL; + } + + set_cmdline_auth_info_getpass(auth_info); + + nt_status = cli_full_connection(&c, lp_netbios_name(), server, + NULL, 0, + "IPC$", "IPC", + get_cmdline_auth_info_username(auth_info), + lp_workgroup(), + get_cmdline_auth_info_password(auth_info), + flags, + get_cmdline_auth_info_signing_state(auth_info)); + + if (!NT_STATUS_IS_OK(nt_status)) { + DEBUG(2,("cli_full_connection failed! (%s)\n", nt_errstr(nt_status))); + return NULL; + } + + return c; +} + +static NTSTATUS send_message(TALLOC_CTX *ctx, struct raw_np_request *request, + struct raw_np_response *response, + struct raw_pipe_client *raw_pipe) +{ + struct raw_pipe_data request_response; + struct ndr_push* push_ndr = ndr_push_init_ctx(ctx); + struct ndr_pull* pull_ndr = NULL; + enum ndr_err_code err; + int ndr_flags = NDR_SCALARS | NDR_BUFFERS; + NTSTATUS status; + + err = ndr_push_raw_np_request(push_ndr, ndr_flags, request); + if (err) { + DEBUG(0,("failed to marshall message! (%d)\n", err)); + status = NT_STATUS_UNSUCCESSFUL; + goto out; + } + + request_response.in = ndr_push_blob(push_ndr); + + status = rawpipe_rawpipeecho(raw_pipe->pipe_handle, ctx, + &request_response); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("request to echo server failed (%s)\n", + nt_errstr(status))); + goto out; + } + + DEBUG(1,("got response, with %d bytes\n", + (uint32_t)request_response.out.length)); + pull_ndr = ndr_pull_init_blob(&request_response.out, ctx); + err = ndr_pull_raw_np_response(pull_ndr, ndr_flags, response); + if (err) { + DEBUG(0,("failed to unmarshall message! (%d)\n", err)); + status = NT_STATUS_UNSUCCESSFUL; + goto out; + } + talloc_free(request_response.out.data); +out: + return status; +} + +/* + * simple test to get the server to echo back the payload carried + * in the request message + */ +static NTSTATUS run_simple_echo_test(TALLOC_CTX *msg_ctx, + struct raw_pipe_client *raw_pipe) +{ + NTSTATUS status; + struct raw_np_request request; + struct raw_np_response response; + uint8 msg1[] = "a test message to be echoed"; + request.description = "simple echo test"; + request.nbytes = ARRAY_SIZE(msg1); + request.payload = msg1; + request.msg = ECHO_TEST; + + status = send_message(msg_ctx, &request, &response, raw_pipe); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("sending message failed (%s)\n", + nt_errstr(status))); + goto out; + } + + if (response.nbytes != ARRAY_SIZE(msg1) || memcmp(msg1, response.payload, ARRAY_SIZE(msg1))) { + DEBUG(0,("got unexpected response")); + NDR_PRINT_DEBUG(raw_np_response, &response); + } +out: + return status; +} + +/* + * simple test to get the server to echo back the current maximum + * data (the client is willing to accept) as specified by the hard coded limit + * TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE + */ +static NTSTATUS run_large_msg_echo_test(TALLOC_CTX *msg_ctx, + struct raw_pipe_client *raw_pipe) +{ + NTSTATUS status; + struct raw_np_request request; + struct raw_np_response response; + request.description = "large message echo test"; + request.nbytes = 0; + request.payload = NULL; + request.msg = ECHO_LARGE_MSG_TEST; + + status = send_message(msg_ctx, &request, &response, raw_pipe); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("sending message failed (%s)\n", + nt_errstr(status))); + goto out; + } + + if (response.nbytes != TSTREAM_MAXDATA - 4) { + DEBUG(0,("got unexpected response size %d\n", response.nbytes)); + NDR_PRINT_DEBUG(raw_np_response, &response); + } +out: + return status; +} + +struct testdata { + NTSTATUS (*test_func)(TALLOC_CTX *msg_ctx, + struct raw_pipe_client *raw_pipe); + const char* name; +} tests[] = { + {run_simple_echo_test,"run_simple_echo_test"}, + {run_large_msg_echo_test,"run_large_msg_echo_test"}, + }; + +int main(int argc, const char *argv[]) +{ + int opt; + NTSTATUS status = NT_STATUS_OK; + + poptContext pc; + struct poptOption long_options[] = { + POPT_AUTOHELP + { "max-protocol", 'm', POPT_ARG_STRING, NULL, 'm', "Set the max protocol level", "LEVEL" }, + + POPT_COMMON_SAMBA + POPT_COMMON_CONNECTION + POPT_COMMON_CREDENTIALS + POPT_TABLEEND + + }; + + struct cli_state *cli; + TALLOC_CTX *frame = talloc_stackframe(); + char *server; + struct user_auth_info *auth_info; + struct raw_pipe_client *raw_pipe_client; + TALLOC_CTX *msg_ctx; + int i; + int pass; + int fail; + load_case_tables(); + + /* set default debug level to 1 regardless of what smb.conf sets */ + setup_logging( "rawpipeechotest", DEBUG_STDERR); + lp_set_cmdline("log level", "1"); + + setlinebuf(stdout); + + lp_load_global(get_dyn_CONFIGFILE()); + load_interfaces(); + + auth_info = user_auth_info_init(frame); + if (auth_info == NULL) { + exit(1); + } + popt_common_set_auth_info(auth_info); + + pc = poptGetContext("rawpipeechotest", argc, argv, long_options, 0); + + while ((opt = poptGetNextOpt(pc)) != -1) { + switch (opt) { + case 'm': + lp_set_cmdline("client max protocol", poptGetOptArg(pc)); + break; + } + } + + /* Make connection to server */ + if(!poptPeekArg(pc)) { + poptPrintUsage(pc, stderr, 0); + return -1; + } + + server = talloc_strdup(frame, poptGetArg(pc) + 2); + if (!server) { + return -1; + } + DEBUG(3,("server %s netbios name %s\n", server, lp_netbios_name())); + cli = connect_server(auth_info, server); + + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("failed to connect to server(%s)\n", + nt_errstr(status))); + return -1; + } + + status = cli_raw_pipe_open_noauth(cli, &ndr_table_rawpipeecho, &raw_pipe_client); + + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("!!failed to open pipe (%s)\n", + nt_errstr(status))); + return -1; + } + msg_ctx = talloc_init(NULL); + pass = 0; + fail = 0; + for (i = 0; i < ARRAY_SIZE(tests); i++) { + status = tests[i].test_func(msg_ctx, raw_pipe_client); + DEBUG(0,("test %d/%d '%s' result %s\n", i + 1, + (int)ARRAY_SIZE(tests), + tests[i].name, + nt_errstr(status))); + if (!NT_STATUS_IS_OK(status)) { + fail++; + } else { + pass++; + } + } + + talloc_free(msg_ctx); + DEBUG(0,("!!%s finished total %d, %d passed, %d failed\n", argv[0], + (int)ARRAY_SIZE(tests), pass, fail)); + return 0; +} diff --git a/source3/wscript_build b/source3/wscript_build index caa62c3..e06dffb 100755 --- a/source3/wscript_build +++ b/source3/wscript_build @@ -1391,6 +1391,16 @@ bld.SAMBA3_BINARY('versiontest', param''', install=False) +bld.SAMBA3_BINARY('rawpipeechotest', + source='utils/rawpipeecho_testcli.c', + deps=''' + talloc + popt_samba3 + rawpipe + libcli_lsa3 + RAW_NDR_RAW_NP_ECHOTEST + krb5samba''') + bld.SAMBA3_BINARY('ntlm_auth', source='''utils/ntlm_auth.c utils/ntlm_auth_diagnostics.c''', deps=''' -- 1.8.1.4