X-Git-Url: http://git.samba.org/samba.git/?p=ira%2Fwip.git;a=blobdiff_plain;f=source3%2Frpcclient%2Frpcclient.c;h=f6d56adecec4bbc63f7abc0173ec986eacebb437;hp=bf016e94c7c69cfe0db33d56e4ba148241f88a0e;hb=31cf2b086a9275955b0480b4b9035dc12671761d;hpb=f071020f5e49837154581c97c5af5f84d0e2de89 diff --git a/source3/rpcclient/rpcclient.c b/source3/rpcclient/rpcclient.c index bf016e94c7c..f6d56adecec 100644 --- a/source3/rpcclient/rpcclient.c +++ b/source3/rpcclient/rpcclient.c @@ -7,7 +7,7 @@ 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 2 of the License, or + 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, @@ -16,15 +16,22 @@ 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, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + along with this program. If not, see . */ #include "includes.h" #include "rpcclient.h" +#include "../libcli/auth/libcli_auth.h" +#include "../librpc/gen_ndr/cli_lsa.h" DOM_SID domain_sid; +static enum pipe_auth_type pipe_default_auth_type = PIPE_AUTH_TYPE_NONE; +static enum dcerpc_AuthLevel pipe_default_auth_level = DCERPC_AUTH_LEVEL_NONE; +static unsigned int timeout = 0; +static enum dcerpc_transport_t default_transport = NCACN_NP; + +struct user_auth_info *rpcclient_auth_info; /* List to hold groups of commands. * @@ -40,7 +47,7 @@ static struct cmd_list { /**************************************************************************** handle completion of commands for readline ****************************************************************************/ -static char **completion_fn(char *text, int start, int end) +static char **completion_fn(const char *text, int start, int end) { #define MAX_COMPLETIONS 100 char **matches; @@ -56,50 +63,58 @@ static char **completion_fn(char *text, int start, int end) #endif /* make sure we have a list of valid commands */ - if (!commands) + if (!commands) { return NULL; + } - matches = (char **)malloc(sizeof(matches[0])*MAX_COMPLETIONS); - if (!matches) return NULL; + matches = SMB_MALLOC_ARRAY(char *, MAX_COMPLETIONS); + if (!matches) { + return NULL; + } - matches[count++] = strdup(text); - if (!matches[0]) return NULL; + matches[count++] = SMB_STRDUP(text); + if (!matches[0]) { + SAFE_FREE(matches); + return NULL; + } - while (commands && count < MAX_COMPLETIONS-1) - { - if (!commands->cmd_set) + while (commands && count < MAX_COMPLETIONS-1) { + if (!commands->cmd_set) { break; + } - for (i=0; commands->cmd_set[i].name; i++) - { + for (i=0; commands->cmd_set[i].name; i++) { if ((strncmp(text, commands->cmd_set[i].name, strlen(text)) == 0) && (( commands->cmd_set[i].returntype == RPC_RTYPE_NTSTATUS && commands->cmd_set[i].ntfn ) || ( commands->cmd_set[i].returntype == RPC_RTYPE_WERROR && - commands->cmd_set[i].wfn))) - { - matches[count] = strdup(commands->cmd_set[i].name); - if (!matches[count]) + commands->cmd_set[i].wfn))) { + matches[count] = SMB_STRDUP(commands->cmd_set[i].name); + if (!matches[count]) { + for (i = 0; i < count; i++) { + SAFE_FREE(matches[count]); + } + SAFE_FREE(matches); return NULL; + } count++; } } - commands = commands->next; } if (count == 2) { SAFE_FREE(matches[0]); - matches[0] = strdup(matches[1]); + matches[0] = SMB_STRDUP(matches[1]); } matches[count] = NULL; return matches; } -static char* next_command (char** cmdstr) +static char *next_command (char **cmdstr) { - static pstring command; + char *command; char *p; if (!cmdstr || !(*cmdstr)) @@ -108,7 +123,7 @@ static char* next_command (char** cmdstr) p = strchr_m(*cmdstr, ';'); if (p) *p = '\0'; - pstrcpy(command, *cmdstr); + command = SMB_STRDUP(*cmdstr); if (p) *cmdstr = p + 1; else @@ -121,49 +136,57 @@ static char* next_command (char** cmdstr) static void fetch_machine_sid(struct cli_state *cli) { - POLICY_HND pol; + struct policy_handle pol; NTSTATUS result = NT_STATUS_OK; - uint32 info_class = 5; - fstring domain_name; - static BOOL got_domain_sid; + static bool got_domain_sid; TALLOC_CTX *mem_ctx; + struct rpc_pipe_client *lsapipe = NULL; + union lsa_PolicyInformation *info = NULL; if (got_domain_sid) return; - if (!(mem_ctx=talloc_init("fetch_machine_sid"))) - { + if (!(mem_ctx=talloc_init("fetch_machine_sid"))) { DEBUG(0,("fetch_machine_sid: talloc_init returned NULL!\n")); goto error; } - - if (!cli_nt_session_open (cli, PI_LSARPC)) { - fprintf(stderr, "could not initialise lsa pipe\n"); + result = cli_rpc_pipe_open_noauth(cli, &ndr_table_lsarpc.syntax_id, + &lsapipe); + if (!NT_STATUS_IS_OK(result)) { + fprintf(stderr, "could not initialise lsa pipe. Error was %s\n", nt_errstr(result) ); goto error; } - result = cli_lsa_open_policy(cli, mem_ctx, True, - SEC_RIGHTS_MAXIMUM_ALLOWED, + result = rpccli_lsa_open_policy(lsapipe, mem_ctx, True, + SEC_FLAG_MAXIMUM_ALLOWED, &pol); if (!NT_STATUS_IS_OK(result)) { goto error; } - result = cli_lsa_query_info_policy(cli, mem_ctx, &pol, info_class, - domain_name, &domain_sid); + result = rpccli_lsa_QueryInfoPolicy(lsapipe, mem_ctx, + &pol, + LSA_POLICY_INFO_ACCOUNT_DOMAIN, + &info); if (!NT_STATUS_IS_OK(result)) { goto error; } got_domain_sid = True; + sid_copy(&domain_sid, info->account_domain.sid); - cli_lsa_close(cli, mem_ctx, &pol); - cli_nt_session_close(cli); + rpccli_lsa_Close(lsapipe, mem_ctx, &pol); + TALLOC_FREE(lsapipe); talloc_destroy(mem_ctx); return; error: + + if (lsapipe) { + TALLOC_FREE(lsapipe); + } + fprintf(stderr, "could not obtain sid for domain %s\n", cli->domain); if (!NT_STATUS_IS_OK(result)) { @@ -175,7 +198,7 @@ static void fetch_machine_sid(struct cli_state *cli) /* List the available commands on a given pipe */ -static NTSTATUS cmd_listcommands(struct cli_state *cli, TALLOC_CTX *mem_ctx, +static NTSTATUS cmd_listcommands(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, int argc, const char **argv) { struct cmd_list *tmp; @@ -202,10 +225,10 @@ static NTSTATUS cmd_listcommands(struct cli_state *cli, TALLOC_CTX *mem_ctx, i = 0; tmp_set++; while(tmp_set->name) { - printf("%20s", tmp_set->name); + printf("%30s", tmp_set->name); tmp_set++; i++; - if (i%4 == 0) + if (i%3 == 0) printf("\n"); } @@ -220,7 +243,7 @@ static NTSTATUS cmd_listcommands(struct cli_state *cli, TALLOC_CTX *mem_ctx, /* Display help on commands */ -static NTSTATUS cmd_help(struct cli_state *cli, TALLOC_CTX *mem_ctx, +static NTSTATUS cmd_help(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, int argc, const char **argv) { struct cmd_list *tmp; @@ -280,7 +303,7 @@ static NTSTATUS cmd_help(struct cli_state *cli, TALLOC_CTX *mem_ctx, /* Change the debug level */ -static NTSTATUS cmd_debuglevel(struct cli_state *cli, TALLOC_CTX *mem_ctx, +static NTSTATUS cmd_debuglevel(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, int argc, const char **argv) { if (argc > 2) { @@ -297,31 +320,243 @@ static NTSTATUS cmd_debuglevel(struct cli_state *cli, TALLOC_CTX *mem_ctx, return NT_STATUS_OK; } -static NTSTATUS cmd_quit(struct cli_state *cli, TALLOC_CTX *mem_ctx, +static NTSTATUS cmd_quit(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, int argc, const char **argv) { exit(0); return NT_STATUS_OK; /* NOTREACHED */ } +static NTSTATUS cmd_set_ss_level(void) +{ + struct cmd_list *tmp; + + /* Close any existing connections not at this level. */ + + for (tmp = cmd_list; tmp; tmp = tmp->next) { + struct cmd_set *tmp_set; + + for (tmp_set = tmp->cmd_set; tmp_set->name; tmp_set++) { + if (tmp_set->rpc_pipe == NULL) { + continue; + } + + if ((tmp_set->rpc_pipe->auth->auth_type + != pipe_default_auth_type) + || (tmp_set->rpc_pipe->auth->auth_level + != pipe_default_auth_level)) { + TALLOC_FREE(tmp_set->rpc_pipe); + tmp_set->rpc_pipe = NULL; + } + } + } + return NT_STATUS_OK; +} + +static NTSTATUS cmd_set_transport(void) +{ + struct cmd_list *tmp; + + /* Close any existing connections not at this level. */ + + for (tmp = cmd_list; tmp; tmp = tmp->next) { + struct cmd_set *tmp_set; + + for (tmp_set = tmp->cmd_set; tmp_set->name; tmp_set++) { + if (tmp_set->rpc_pipe == NULL) { + continue; + } + + if (tmp_set->rpc_pipe->transport->transport != default_transport) { + TALLOC_FREE(tmp_set->rpc_pipe); + tmp_set->rpc_pipe = NULL; + } + } + } + return NT_STATUS_OK; +} + +static NTSTATUS cmd_sign(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + const char *type = "NTLMSSP"; + + pipe_default_auth_level = DCERPC_AUTH_LEVEL_INTEGRITY; + pipe_default_auth_type = PIPE_AUTH_TYPE_NTLMSSP; + + if (argc > 2) { + printf("Usage: %s [NTLMSSP|NTLMSSP_SPNEGO|SCHANNEL]\n", argv[0]); + return NT_STATUS_OK; + } + + if (argc == 2) { + type = argv[1]; + if (strequal(type, "NTLMSSP")) { + pipe_default_auth_type = PIPE_AUTH_TYPE_NTLMSSP; + } else if (strequal(type, "NTLMSSP_SPNEGO")) { + pipe_default_auth_type = PIPE_AUTH_TYPE_SPNEGO_NTLMSSP; + } else if (strequal(type, "SCHANNEL")) { + pipe_default_auth_type = PIPE_AUTH_TYPE_SCHANNEL; + } else { + printf("unknown type %s\n", type); + return NT_STATUS_INVALID_LEVEL; + } + } + + d_printf("Setting %s - sign\n", type); + + return cmd_set_ss_level(); +} + +static NTSTATUS cmd_seal(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + const char *type = "NTLMSSP"; + + pipe_default_auth_level = DCERPC_AUTH_LEVEL_PRIVACY; + pipe_default_auth_type = PIPE_AUTH_TYPE_NTLMSSP; + + if (argc > 2) { + printf("Usage: %s [NTLMSSP|NTLMSSP_SPNEGO|SCHANNEL]\n", argv[0]); + return NT_STATUS_OK; + } + + if (argc == 2) { + type = argv[1]; + if (strequal(type, "NTLMSSP")) { + pipe_default_auth_type = PIPE_AUTH_TYPE_NTLMSSP; + } else if (strequal(type, "NTLMSSP_SPNEGO")) { + pipe_default_auth_type = PIPE_AUTH_TYPE_SPNEGO_NTLMSSP; + } else if (strequal(type, "SCHANNEL")) { + pipe_default_auth_type = PIPE_AUTH_TYPE_SCHANNEL; + } else { + printf("unknown type %s\n", type); + return NT_STATUS_INVALID_LEVEL; + } + } + + d_printf("Setting %s - sign and seal\n", type); + + return cmd_set_ss_level(); +} + +static NTSTATUS cmd_timeout(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + struct cmd_list *tmp; + + if (argc > 2) { + printf("Usage: %s timeout\n", argv[0]); + return NT_STATUS_OK; + } + + if (argc == 2) { + timeout = atoi(argv[1]); + + for (tmp = cmd_list; tmp; tmp = tmp->next) { + + struct cmd_set *tmp_set; + + for (tmp_set = tmp->cmd_set; tmp_set->name; tmp_set++) { + if (tmp_set->rpc_pipe == NULL) { + continue; + } + + rpccli_set_timeout(tmp_set->rpc_pipe, timeout); + } + } + } + + printf("timeout is %d\n", timeout); + + return NT_STATUS_OK; +} + + +static NTSTATUS cmd_none(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + pipe_default_auth_level = DCERPC_AUTH_LEVEL_NONE; + pipe_default_auth_type = PIPE_AUTH_TYPE_NONE; + + return cmd_set_ss_level(); +} + +static NTSTATUS cmd_schannel(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + d_printf("Setting schannel - sign and seal\n"); + pipe_default_auth_level = DCERPC_AUTH_LEVEL_PRIVACY; + pipe_default_auth_type = PIPE_AUTH_TYPE_SCHANNEL; + + return cmd_set_ss_level(); +} + +static NTSTATUS cmd_schannel_sign(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + d_printf("Setting schannel - sign only\n"); + pipe_default_auth_level = DCERPC_AUTH_LEVEL_INTEGRITY; + pipe_default_auth_type = PIPE_AUTH_TYPE_SCHANNEL; + + return cmd_set_ss_level(); +} + +static NTSTATUS cmd_choose_transport(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + NTSTATUS status; + + if (argc != 2) { + printf("Usage: %s [NCACN_NP|NCACN_IP_TCP]\n", argv[0]); + return NT_STATUS_OK; + } + + if (strequal(argv[1], "NCACN_NP")) { + default_transport = NCACN_NP; + } else if (strequal(argv[1], "NCACN_IP_TCP")) { + default_transport = NCACN_IP_TCP; + } else { + printf("transport type: %s unknown or not supported\n", argv[1]); + return NT_STATUS_NOT_SUPPORTED; + } + + status = cmd_set_transport(); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + printf("default transport is now: %s\n", argv[1]); + + return NT_STATUS_OK; +} + /* Built in rpcclient commands */ static struct cmd_set rpcclient_commands[] = { { "GENERAL OPTIONS" }, - { "help", RPC_RTYPE_NTSTATUS, cmd_help, NULL, -1, "Get help on commands", "[command]" }, - { "?", RPC_RTYPE_NTSTATUS, cmd_help, NULL, -1, "Get help on commands", "[command]" }, - { "debuglevel", RPC_RTYPE_NTSTATUS, cmd_debuglevel, NULL, -1, "Set debug level", "level" }, - { "list", RPC_RTYPE_NTSTATUS, cmd_listcommands, NULL, -1, "List available commands on ", "pipe" }, - { "exit", RPC_RTYPE_NTSTATUS, cmd_quit, NULL, -1, "Exit program", "" }, - { "quit", RPC_RTYPE_NTSTATUS, cmd_quit, NULL, -1, "Exit program", "" }, + { "help", RPC_RTYPE_NTSTATUS, cmd_help, NULL, NULL, NULL, "Get help on commands", "[command]" }, + { "?", RPC_RTYPE_NTSTATUS, cmd_help, NULL, NULL, NULL, "Get help on commands", "[command]" }, + { "debuglevel", RPC_RTYPE_NTSTATUS, cmd_debuglevel, NULL, NULL, NULL, "Set debug level", "level" }, + { "debug", RPC_RTYPE_NTSTATUS, cmd_debuglevel, NULL, NULL, NULL, "Set debug level", "level" }, + { "list", RPC_RTYPE_NTSTATUS, cmd_listcommands, NULL, NULL, NULL, "List available commands on ", "pipe" }, + { "exit", RPC_RTYPE_NTSTATUS, cmd_quit, NULL, NULL, NULL, "Exit program", "" }, + { "quit", RPC_RTYPE_NTSTATUS, cmd_quit, NULL, NULL, NULL, "Exit program", "" }, + { "sign", RPC_RTYPE_NTSTATUS, cmd_sign, NULL, NULL, NULL, "Force RPC pipe connections to be signed", "" }, + { "seal", RPC_RTYPE_NTSTATUS, cmd_seal, NULL, NULL, NULL, "Force RPC pipe connections to be sealed", "" }, + { "schannel", RPC_RTYPE_NTSTATUS, cmd_schannel, NULL, NULL, NULL, "Force RPC pipe connections to be sealed with 'schannel'. Assumes valid machine account to this domain controller.", "" }, + { "schannelsign", RPC_RTYPE_NTSTATUS, cmd_schannel_sign, NULL, NULL, NULL, "Force RPC pipe connections to be signed (not sealed) with 'schannel'. Assumes valid machine account to this domain controller.", "" }, + { "timeout", RPC_RTYPE_NTSTATUS, cmd_timeout, NULL, NULL, NULL, "Set timeout (in milliseonds) for RPC operations", "" }, + { "transport", RPC_RTYPE_NTSTATUS, cmd_choose_transport, NULL, NULL, NULL, "Choose ncacn transport for RPC operations", "" }, + { "none", RPC_RTYPE_NTSTATUS, cmd_none, NULL, NULL, NULL, "Force RPC pipe connections to have no special properties", "" }, { NULL } }; static struct cmd_set separator_command[] = { - { "---------------", MAX_RPC_RETURN_TYPE, NULL, NULL, -1, "----------------------" }, + { "---------------", MAX_RPC_RETURN_TYPE, NULL, NULL, NULL, NULL, "----------------------" }, { NULL } }; @@ -334,9 +569,15 @@ extern struct cmd_set spoolss_commands[]; extern struct cmd_set netlogon_commands[]; extern struct cmd_set srvsvc_commands[]; extern struct cmd_set dfs_commands[]; -extern struct cmd_set reg_commands[]; extern struct cmd_set ds_commands[]; extern struct cmd_set echo_commands[]; +extern struct cmd_set epmapper_commands[]; +extern struct cmd_set shutdown_commands[]; +extern struct cmd_set test_commands[]; +extern struct cmd_set wkssvc_commands[]; +extern struct cmd_set ntsvcs_commands[]; +extern struct cmd_set drsuapi_commands[]; +extern struct cmd_set eventlog_commands[]; static struct cmd_set *rpcclient_command_list[] = { rpcclient_commands, @@ -347,8 +588,14 @@ static struct cmd_set *rpcclient_command_list[] = { netlogon_commands, srvsvc_commands, dfs_commands, - reg_commands, echo_commands, + epmapper_commands, + shutdown_commands, + test_commands, + wkssvc_commands, + ntsvcs_commands, + drsuapi_commands, + eventlog_commands, NULL }; @@ -356,7 +603,7 @@ static void add_command_set(struct cmd_set *cmd_set) { struct cmd_list *entry; - if (!(entry = (struct cmd_list *)malloc(sizeof(struct cmd_list)))) { + if (!(entry = SMB_MALLOC_P(struct cmd_list))) { DEBUG(0, ("out of memory\n")); return; } @@ -374,11 +621,13 @@ static void add_command_set(struct cmd_set *cmd_set) * @param cmd Command to run, as a single string. **/ static NTSTATUS do_cmd(struct cli_state *cli, + struct user_auth_info *auth_info, struct cmd_set *cmd_entry, + struct dcerpc_binding *binding, int argc, char **argv) { - NTSTATUS ntresult; - WERROR wresult; + NTSTATUS ntresult; + WERROR wresult; TALLOC_CTX *mem_ctx; @@ -386,58 +635,115 @@ static NTSTATUS do_cmd(struct cli_state *cli, if (!(mem_ctx = talloc_init("do_cmd"))) { DEBUG(0, ("talloc_init() failed\n")); - return NT_STATUS_UNSUCCESSFUL; + return NT_STATUS_NO_MEMORY; } /* Open pipe */ - if (cmd_entry->pipe_idx == PI_NETLOGON) { - uchar trust_password[16]; - uint32 sec_channel_type; - - if (!secrets_fetch_trust_account_password(lp_workgroup(), - trust_password, - NULL, &sec_channel_type)) { - return NT_STATUS_UNSUCCESSFUL; + if ((cmd_entry->interface != NULL) && (cmd_entry->rpc_pipe == NULL)) { + switch (pipe_default_auth_type) { + case PIPE_AUTH_TYPE_NONE: + ntresult = cli_rpc_pipe_open_noauth_transport( + cli, default_transport, + cmd_entry->interface, + &cmd_entry->rpc_pipe); + break; + case PIPE_AUTH_TYPE_SPNEGO_NTLMSSP: + ntresult = cli_rpc_pipe_open_spnego_ntlmssp( + cli, cmd_entry->interface, + default_transport, + pipe_default_auth_level, + get_cmdline_auth_info_domain(auth_info), + get_cmdline_auth_info_username(auth_info), + get_cmdline_auth_info_password(auth_info), + &cmd_entry->rpc_pipe); + break; + case PIPE_AUTH_TYPE_NTLMSSP: + ntresult = cli_rpc_pipe_open_ntlmssp( + cli, cmd_entry->interface, + default_transport, + pipe_default_auth_level, + get_cmdline_auth_info_domain(auth_info), + get_cmdline_auth_info_username(auth_info), + get_cmdline_auth_info_password(auth_info), + &cmd_entry->rpc_pipe); + break; + case PIPE_AUTH_TYPE_SCHANNEL: + ntresult = cli_rpc_pipe_open_schannel( + cli, cmd_entry->interface, + default_transport, + pipe_default_auth_level, + get_cmdline_auth_info_domain(auth_info), + &cmd_entry->rpc_pipe); + break; + default: + DEBUG(0, ("Could not initialise %s. Invalid " + "auth type %u\n", + get_pipe_name_from_syntax( + talloc_tos(), + cmd_entry->interface), + pipe_default_auth_type )); + return NT_STATUS_UNSUCCESSFUL; } - - if (!cli_nt_open_netlogon(cli, trust_password, - sec_channel_type)) { - DEBUG(0, ("Could not initialise NETLOGON pipe\n")); - return NT_STATUS_UNSUCCESSFUL; + if (!NT_STATUS_IS_OK(ntresult)) { + DEBUG(0, ("Could not initialise %s. Error was %s\n", + get_pipe_name_from_syntax( + talloc_tos(), cmd_entry->interface), + nt_errstr(ntresult) )); + return ntresult; } - } else { - if (cmd_entry->pipe_idx != -1) { - if (!cli_nt_session_open(cli, cmd_entry->pipe_idx)) { - DEBUG(0, ("Could not initialise %s\n", - get_pipe_name_from_index(cmd_entry->pipe_idx))); - return NT_STATUS_UNSUCCESSFUL; + + if (ndr_syntax_id_equal(cmd_entry->interface, + &ndr_table_netlogon.syntax_id)) { + uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS; + enum netr_SchannelType sec_channel_type; + uchar trust_password[16]; + const char *machine_account; + + if (!get_trust_pw_hash(get_cmdline_auth_info_domain(auth_info), + trust_password, &machine_account, + &sec_channel_type)) + { + return NT_STATUS_CANT_ACCESS_DOMAIN_INFO; + } + + ntresult = rpccli_netlogon_setup_creds(cmd_entry->rpc_pipe, + cli->desthost, /* server name */ + get_cmdline_auth_info_domain(auth_info), /* domain */ + global_myname(), /* client name */ + machine_account, /* machine account name */ + trust_password, + sec_channel_type, + &neg_flags); + + if (!NT_STATUS_IS_OK(ntresult)) { + DEBUG(0, ("Could not initialise credentials for %s.\n", + get_pipe_name_from_syntax( + talloc_tos(), + cmd_entry->interface))); + return ntresult; } } } - /* Run command */ + /* Run command */ - if ( cmd_entry->returntype == RPC_RTYPE_NTSTATUS ) { - ntresult = cmd_entry->ntfn(cli, mem_ctx, argc, (const char **) argv); - if (!NT_STATUS_IS_OK(ntresult)) { - printf("result was %s\n", nt_errstr(ntresult)); - } - } else { - wresult = cmd_entry->wfn( cli, mem_ctx, argc, (const char **) argv); - /* print out the DOS error */ - if (!W_ERROR_IS_OK(wresult)) { - printf( "result was %s\n", dos_errstr(wresult)); - } - ntresult = W_ERROR_IS_OK(wresult)?NT_STATUS_OK:NT_STATUS_UNSUCCESSFUL; - } - + if ( cmd_entry->returntype == RPC_RTYPE_NTSTATUS ) { + ntresult = cmd_entry->ntfn(cmd_entry->rpc_pipe, mem_ctx, argc, (const char **) argv); + if (!NT_STATUS_IS_OK(ntresult)) { + printf("result was %s\n", nt_errstr(ntresult)); + } + } else { + wresult = cmd_entry->wfn(cmd_entry->rpc_pipe, mem_ctx, argc, (const char **) argv); + /* print out the DOS error */ + if (!W_ERROR_IS_OK(wresult)) { + printf( "result was %s\n", win_errstr(wresult)); + } + ntresult = W_ERROR_IS_OK(wresult)?NT_STATUS_OK:NT_STATUS_UNSUCCESSFUL; + } /* Cleanup */ - if (cmd_entry->pipe_idx != -1) - cli_nt_session_close(cli); - talloc_destroy(mem_ctx); return ntresult; @@ -449,7 +755,10 @@ static NTSTATUS do_cmd(struct cli_state *cli, * * @returns The NTSTATUS from running the command. **/ -static NTSTATUS process_cmd(struct cli_state *cli, char *cmd) +static NTSTATUS process_cmd(struct user_auth_info *auth_info, + struct cli_state *cli, + struct dcerpc_binding *binding, + char *cmd) { struct cmd_list *temp_list; NTSTATUS result = NT_STATUS_OK; @@ -475,7 +784,8 @@ static NTSTATUS process_cmd(struct cli_state *cli, char *cmd) goto out_free; } - result = do_cmd(cli, temp_set, argc, argv); + result = do_cmd(cli, auth_info, temp_set, + binding, argc, argv); goto out_free; } @@ -494,14 +804,12 @@ out_free: } */ - if (argv) { - /* NOTE: popt allocates the whole argv, including the - * strings, as a single block. So a single free is - * enough to release it -- we don't free the - * individual strings. rtfm. */ - free(argv); - } - + /* NOTE: popt allocates the whole argv, including the + * strings, as a single block. So a single free is + * enough to release it -- we don't free the + * individual strings. rtfm. */ + free(argv); + return result; } @@ -510,15 +818,22 @@ out_free: int main(int argc, char *argv[]) { - BOOL interactive = True; int opt; static char *cmdstr = NULL; const char *server; - struct cli_state *cli; + struct cli_state *cli = NULL; static char *opt_ipaddr=NULL; struct cmd_set **cmd_set; - struct in_addr server_ip; + struct sockaddr_storage server_ss; NTSTATUS nt_status; + static int opt_port = 0; + fstring new_workgroup; + int result = 0; + TALLOC_CTX *frame = talloc_stackframe(); + uint32_t flags = 0; + struct dcerpc_binding *binding = NULL; + const char *binding_string = NULL; + char *user, *domain, *q; /* make sure the vars that get altered (4th field) are in a fixed location or certain compilers complain */ @@ -527,16 +842,29 @@ out_free: POPT_AUTOHELP {"command", 'c', POPT_ARG_STRING, &cmdstr, 'c', "Execute semicolon separated cmds", "COMMANDS"}, {"dest-ip", 'I', POPT_ARG_STRING, &opt_ipaddr, 'I', "Specify destination IP address", "IP"}, + {"port", 'p', POPT_ARG_INT, &opt_port, 'p', "Specify port number", "PORT"}, POPT_COMMON_SAMBA POPT_COMMON_CONNECTION POPT_COMMON_CREDENTIALS POPT_TABLEEND }; - ZERO_STRUCT(server_ip); + load_case_tables(); + + zero_sockaddr(&server_ss); setlinebuf(stdout); + /* the following functions are part of the Samba debugging + facilities. See lib/debug.c */ + setup_logging("rpcclient", True); + + rpcclient_auth_info = user_auth_info_init(frame); + if (rpcclient_auth_info == NULL) { + exit(1); + } + popt_common_set_auth_info(rpcclient_auth_info); + /* Parse options */ pc = poptGetContext("rpcclient", argc, (const char **) argv, @@ -544,17 +872,20 @@ out_free: if (argc == 1) { poptPrintHelp(pc, stderr, 0); - return 0; + goto done; } - + while((opt = poptGetNextOpt(pc)) != -1) { switch (opt) { case 'I': - if ( (server_ip.s_addr=inet_addr(opt_ipaddr)) == INADDR_NONE ) { + if (!interpret_string_addr(&server_ss, + opt_ipaddr, + AI_NUMERICHOST)) { fprintf(stderr, "%s not a valid IP address\n", opt_ipaddr); - return 1; + result = 1; + goto done; } } } @@ -563,57 +894,150 @@ out_free: than one unparsed argument is present. */ server = poptGetArg(pc); - + if (!server || poptGetArg(pc)) { poptPrintHelp(pc, stderr, 0); - return 1; + result = 1; + goto done; } poptFreeContext(pc); - /* the following functions are part of the Samba debugging - facilities. See lib/debug.c */ - setup_logging("rpcclient", interactive); - if (!interactive) - reopen_logs(); - - /* Load smb.conf file */ + load_interfaces(); - if (!lp_load(dyn_CONFIGFILE,True,False,False)) - fprintf(stderr, "Can't load %s\n", dyn_CONFIGFILE); + if (!init_names()) { + result = 1; + goto done; + } - load_interfaces(); + /* save the workgroup... + + FIXME!! do we need to do this for other options as well + (or maybe a generic way to keep lp_load() from overwriting + everything)? */ + + fstrcpy( new_workgroup, lp_workgroup() ); + + /* Load smb.conf file */ + + if (!lp_load(get_dyn_CONFIGFILE(),True,False,False,True)) + fprintf(stderr, "Can't load %s\n", get_dyn_CONFIGFILE()); - if (!init_names()) - return 1; + if ( strlen(new_workgroup) != 0 ) + set_global_myworkgroup( new_workgroup ); /* * Get password * from stdin if necessary */ - if (!cmdline_auth_info.got_pass) { - char *pass = getpass("Password:"); - if (pass) { - pstrcpy(cmdline_auth_info.password, pass); + if (get_cmdline_auth_info_use_machine_account(rpcclient_auth_info) && + !set_cmdline_auth_info_machine_account_creds(rpcclient_auth_info)) { + result = 1; + goto done; + } + + set_cmdline_auth_info_getpass(rpcclient_auth_info); + + if ((server[0] == '/' && server[1] == '/') || + (server[0] == '\\' && server[1] == '\\')) { + server += 2; + } + + nt_status = dcerpc_parse_binding(frame, server, &binding); + + if (!NT_STATUS_IS_OK(nt_status)) { + + binding_string = talloc_asprintf(frame, "ncacn_np:%s", + strip_hostname(server)); + if (!binding_string) { + result = 1; + goto done; + } + + nt_status = dcerpc_parse_binding(frame, binding_string, &binding); + if (!NT_STATUS_IS_OK(nt_status)) { + result = -1; + goto done; } } - - nt_status = cli_full_connection(&cli, global_myname(), server, - opt_ipaddr ? &server_ip : NULL, 0, - "IPC$", "IPC", - cmdline_auth_info.username, lp_workgroup(), - cmdline_auth_info.password, 0, NULL); - + + if (binding->transport == NCA_UNKNOWN) { + binding->transport = NCACN_NP; + } + + if (binding->flags & DCERPC_SIGN) { + pipe_default_auth_level = DCERPC_AUTH_LEVEL_INTEGRITY; + pipe_default_auth_type = PIPE_AUTH_TYPE_NTLMSSP; + } + if (binding->flags & DCERPC_SEAL) { + pipe_default_auth_level = DCERPC_AUTH_LEVEL_PRIVACY; + pipe_default_auth_type = PIPE_AUTH_TYPE_NTLMSSP; + } + if (binding->flags & DCERPC_AUTH_SPNEGO) { + pipe_default_auth_type = PIPE_AUTH_TYPE_SPNEGO_NTLMSSP; + } + if (binding->flags & DCERPC_AUTH_NTLM) { + pipe_default_auth_type = PIPE_AUTH_TYPE_NTLMSSP; + } + if (binding->flags & DCERPC_AUTH_KRB5) { + pipe_default_auth_type = PIPE_AUTH_TYPE_SPNEGO_KRB5; + } + + if (get_cmdline_auth_info_use_kerberos(rpcclient_auth_info)) { + flags |= CLI_FULL_CONNECTION_USE_KERBEROS | + CLI_FULL_CONNECTION_FALLBACK_AFTER_KERBEROS; + } + + user = talloc_strdup(frame, get_cmdline_auth_info_username(rpcclient_auth_info)); + SMB_ASSERT(user != NULL); + domain = talloc_strdup(frame, lp_workgroup()); + SMB_ASSERT(domain != NULL); + set_cmdline_auth_info_domain(rpcclient_auth_info, domain); + + if ((q = strchr_m(user,'\\'))) { + *q = 0; + set_cmdline_auth_info_domain(rpcclient_auth_info, user); + set_cmdline_auth_info_username(rpcclient_auth_info, q+1); + } + + + nt_status = cli_full_connection(&cli, global_myname(), binding->host, + opt_ipaddr ? &server_ss : NULL, opt_port, + "IPC$", "IPC", + get_cmdline_auth_info_username(rpcclient_auth_info), + get_cmdline_auth_info_domain(rpcclient_auth_info), + get_cmdline_auth_info_password(rpcclient_auth_info), + flags, + get_cmdline_auth_info_signing_state(rpcclient_auth_info), + NULL); + if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(0,("Cannot connect to server. Error was %s\n", nt_errstr(nt_status))); - return 1; + result = 1; + goto done; + } + + if (get_cmdline_auth_info_smb_encrypt(rpcclient_auth_info)) { + nt_status = cli_cm_force_encryption(cli, + get_cmdline_auth_info_username(rpcclient_auth_info), + get_cmdline_auth_info_password(rpcclient_auth_info), + get_cmdline_auth_info_domain(rpcclient_auth_info), + "IPC$"); + if (!NT_STATUS_IS_OK(nt_status)) { + result = 1; + goto done; + } } +#if 0 /* COMMENT OUT FOR TESTING */ memset(cmdline_auth_info.password,'X',sizeof(cmdline_auth_info.password)); +#endif /* Load command lists */ + timeout = cli_set_timeout(cli, 10000); + cmd_set = rpcclient_command_list; while(*cmd_set) { @@ -622,38 +1046,46 @@ out_free: cmd_set++; } + default_transport = binding->transport; + fetch_machine_sid(cli); - + /* Do anything specified with -c */ if (cmdstr && cmdstr[0]) { char *cmd; char *p = cmdstr; - + + result = 0; + while((cmd=next_command(&p)) != NULL) { - process_cmd(cli, cmd); + NTSTATUS cmd_result = process_cmd(rpcclient_auth_info, cli, + binding, cmd); + SAFE_FREE(cmd); + result = NT_STATUS_IS_ERR(cmd_result); } - - cli_shutdown(cli); - return 0; + + goto done; } /* Loop around accepting commands */ while(1) { - pstring prompt; - char *line; + char *line = NULL; - slprintf(prompt, sizeof(prompt) - 1, "rpcclient $> "); - - line = smb_readline(prompt, NULL, completion_fn); + line = smb_readline("rpcclient $> ", NULL, completion_fn); if (line == NULL) break; if (line[0] != '\n') - process_cmd(cli, line); + process_cmd(rpcclient_auth_info, cli, binding, line); + SAFE_FREE(line); } - - cli_shutdown(cli); - return 0; + +done: + if (cli != NULL) { + cli_shutdown(cli); + } + TALLOC_FREE(frame); + return result; }