2 Unix SMB/CIFS implementation.
5 Copyright (C) Tim Potter 2000-2001
6 Copyright (C) Martin Pool 2003
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "rpcclient.h"
29 /* List to hold groups of commands.
31 * Commands are defined in a list of arrays: arrays are easy to
32 * statically declare, and lists are easier to dynamically extend.
35 static struct cmd_list {
36 struct cmd_list *prev, *next;
37 struct cmd_set *cmd_set;
40 /*****************************************************************************
42 ****************************************************************************/
44 void become_root( void )
49 void unbecome_root( void )
55 /****************************************************************************
56 handle completion of commands for readline
57 ****************************************************************************/
58 static char **completion_fn(char *text, int start, int end)
60 #define MAX_COMPLETIONS 100
63 struct cmd_list *commands = cmd_list;
66 /* FIXME!!! -- what to do when completing argument? */
67 /* for words not at the start of the line fallback
68 to filename completion */
73 /* make sure we have a list of valid commands */
77 matches = (char **)malloc(sizeof(matches[0])*MAX_COMPLETIONS);
78 if (!matches) return NULL;
80 matches[count++] = strdup(text);
81 if (!matches[0]) return NULL;
83 while (commands && count < MAX_COMPLETIONS-1)
85 if (!commands->cmd_set)
88 for (i=0; commands->cmd_set[i].name; i++)
90 if ((strncmp(text, commands->cmd_set[i].name, strlen(text)) == 0) &&
91 (( commands->cmd_set[i].returntype == RPC_RTYPE_NTSTATUS &&
92 commands->cmd_set[i].ntfn ) ||
93 ( commands->cmd_set[i].returntype == RPC_RTYPE_WERROR &&
94 commands->cmd_set[i].wfn)))
96 matches[count] = strdup(commands->cmd_set[i].name);
103 commands = commands->next;
108 SAFE_FREE(matches[0]);
109 matches[0] = strdup(matches[1]);
111 matches[count] = NULL;
115 static char* next_command (char** cmdstr)
117 static pstring command;
120 if (!cmdstr || !(*cmdstr))
123 p = strchr_m(*cmdstr, ';');
126 pstrcpy(command, *cmdstr);
135 /* Fetch the SID for this computer */
137 static void fetch_machine_sid(struct cli_state *cli)
140 NTSTATUS result = NT_STATUS_OK;
141 uint32 info_class = 5;
143 static BOOL got_domain_sid;
146 if (got_domain_sid) return;
148 if (!(mem_ctx=talloc_init("fetch_machine_sid")))
150 DEBUG(0,("fetch_machine_sid: talloc_init returned NULL!\n"));
155 if (!cli_nt_session_open (cli, PI_LSARPC)) {
156 fprintf(stderr, "could not initialise lsa pipe\n");
160 result = cli_lsa_open_policy(cli, mem_ctx, True,
161 SEC_RIGHTS_MAXIMUM_ALLOWED,
163 if (!NT_STATUS_IS_OK(result)) {
167 result = cli_lsa_query_info_policy(cli, mem_ctx, &pol, info_class,
168 domain_name, &domain_sid);
169 if (!NT_STATUS_IS_OK(result)) {
173 got_domain_sid = True;
175 cli_lsa_close(cli, mem_ctx, &pol);
176 cli_nt_session_close(cli);
177 talloc_destroy(mem_ctx);
182 fprintf(stderr, "could not obtain sid for domain %s\n", cli->domain);
184 if (!NT_STATUS_IS_OK(result)) {
185 fprintf(stderr, "error: %s\n", nt_errstr(result));
191 /* List the available commands on a given pipe */
193 static NTSTATUS cmd_listcommands(struct cli_state *cli, TALLOC_CTX *mem_ctx,
194 int argc, const char **argv)
196 struct cmd_list *tmp;
197 struct cmd_set *tmp_set;
203 printf("Usage: %s <pipe>\n", argv[0]);
207 /* Help on one command */
209 for (tmp = cmd_list; tmp; tmp = tmp->next)
211 tmp_set = tmp->cmd_set;
213 if (!StrCaseCmp(argv[1], tmp_set->name))
215 printf("Available commands on the %s pipe:\n\n", tmp_set->name);
219 while(tmp_set->name) {
220 printf("%20s", tmp_set->name);
227 /* drop out of the loop */
236 /* Display help on commands */
238 static NTSTATUS cmd_help(struct cli_state *cli, TALLOC_CTX *mem_ctx,
239 int argc, const char **argv)
241 struct cmd_list *tmp;
242 struct cmd_set *tmp_set;
247 printf("Usage: %s [command]\n", argv[0]);
251 /* Help on one command */
254 for (tmp = cmd_list; tmp; tmp = tmp->next) {
256 tmp_set = tmp->cmd_set;
258 while(tmp_set->name) {
259 if (strequal(argv[1], tmp_set->name)) {
260 if (tmp_set->usage &&
262 printf("%s\n", tmp_set->usage);
264 printf("No help for %s\n", tmp_set->name);
273 printf("No such command: %s\n", argv[1]);
277 /* List all commands */
279 for (tmp = cmd_list; tmp; tmp = tmp->next) {
281 tmp_set = tmp->cmd_set;
283 while(tmp_set->name) {
285 printf("%15s\t\t%s\n", tmp_set->name,
286 tmp_set->description ? tmp_set->description:
296 /* Change the debug level */
298 static NTSTATUS cmd_debuglevel(struct cli_state *cli, TALLOC_CTX *mem_ctx,
299 int argc, const char **argv)
302 printf("Usage: %s [debuglevel]\n", argv[0]);
307 DEBUGLEVEL = atoi(argv[1]);
310 printf("debuglevel is %d\n", DEBUGLEVEL);
315 static NTSTATUS cmd_quit(struct cli_state *cli, TALLOC_CTX *mem_ctx,
316 int argc, const char **argv)
319 return NT_STATUS_OK; /* NOTREACHED */
322 /* Built in rpcclient commands */
324 static struct cmd_set rpcclient_commands[] = {
326 { "GENERAL OPTIONS" },
328 { "help", RPC_RTYPE_NTSTATUS, cmd_help, NULL, -1, "Get help on commands", "[command]" },
329 { "?", RPC_RTYPE_NTSTATUS, cmd_help, NULL, -1, "Get help on commands", "[command]" },
330 { "debuglevel", RPC_RTYPE_NTSTATUS, cmd_debuglevel, NULL, -1, "Set debug level", "level" },
331 { "list", RPC_RTYPE_NTSTATUS, cmd_listcommands, NULL, -1, "List available commands on <pipe>", "pipe" },
332 { "exit", RPC_RTYPE_NTSTATUS, cmd_quit, NULL, -1, "Exit program", "" },
333 { "quit", RPC_RTYPE_NTSTATUS, cmd_quit, NULL, -1, "Exit program", "" },
338 static struct cmd_set separator_command[] = {
339 { "---------------", MAX_RPC_RETURN_TYPE, NULL, NULL, -1, "----------------------" },
344 /* Various pipe commands */
346 extern struct cmd_set lsarpc_commands[];
347 extern struct cmd_set samr_commands[];
348 extern struct cmd_set spoolss_commands[];
349 extern struct cmd_set netlogon_commands[];
350 extern struct cmd_set srvsvc_commands[];
351 extern struct cmd_set dfs_commands[];
352 extern struct cmd_set reg_commands[];
353 extern struct cmd_set ds_commands[];
354 extern struct cmd_set echo_commands[];
356 static struct cmd_set *rpcclient_command_list[] = {
370 static void add_command_set(struct cmd_set *cmd_set)
372 struct cmd_list *entry;
374 if (!(entry = (struct cmd_list *)malloc(sizeof(struct cmd_list)))) {
375 DEBUG(0, ("out of memory\n"));
381 entry->cmd_set = cmd_set;
382 DLIST_ADD(cmd_list, entry);
387 * Call an rpcclient function, passing an argv array.
389 * @param cmd Command to run, as a single string.
391 static NTSTATUS do_cmd(struct cli_state *cli,
392 struct cmd_set *cmd_entry,
393 int argc, char **argv)
402 if (!(mem_ctx = talloc_init("do_cmd"))) {
403 DEBUG(0, ("talloc_init() failed\n"));
404 return NT_STATUS_UNSUCCESSFUL;
409 if (cmd_entry->pipe_idx != -1) {
410 if (!cli_nt_session_open(cli, cmd_entry->pipe_idx)) {
411 DEBUG(0, ("Could not initialise %s\n",
412 get_pipe_name_from_index(cmd_entry->pipe_idx)));
413 return NT_STATUS_UNSUCCESSFUL;
417 if (cmd_entry->pipe_idx == PI_NETLOGON) {
418 uchar trust_password[16];
419 uint32 sec_channel_type;
421 if (!secrets_fetch_trust_account_password(lp_workgroup(),
423 NULL, &sec_channel_type)) {
424 return NT_STATUS_UNSUCCESSFUL;
427 if (!NT_STATUS_IS_OK(cli_nt_establish_netlogon(cli, sec_channel_type,
429 DEBUG(0, ("Could not initialise NETLOGON pipe\n"));
430 return NT_STATUS_UNSUCCESSFUL;
436 if ( cmd_entry->returntype == RPC_RTYPE_NTSTATUS ) {
437 ntresult = cmd_entry->ntfn(cli, mem_ctx, argc, (const char **) argv);
438 if (!NT_STATUS_IS_OK(ntresult)) {
439 printf("result was %s\n", nt_errstr(ntresult));
442 wresult = cmd_entry->wfn( cli, mem_ctx, argc, (const char **) argv);
443 /* print out the DOS error */
444 if (!W_ERROR_IS_OK(wresult)) {
445 printf( "result was %s\n", dos_errstr(wresult));
447 ntresult = W_ERROR_IS_OK(wresult)?NT_STATUS_OK:NT_STATUS_UNSUCCESSFUL;
453 if (cmd_entry->pipe_idx != -1)
454 cli_nt_session_close(cli);
456 talloc_destroy(mem_ctx);
463 * Process a command entered at the prompt or as part of -c
465 * @returns The NTSTATUS from running the command.
467 static NTSTATUS process_cmd(struct cli_state *cli, char *cmd)
469 struct cmd_list *temp_list;
470 NTSTATUS result = NT_STATUS_OK;
475 if ((ret = poptParseArgvString(cmd, &argc, (const char ***) &argv)) != 0) {
476 fprintf(stderr, "rpcclient: %s\n", poptStrerror(ret));
477 return NT_STATUS_UNSUCCESSFUL;
481 /* Walk through a dlist of arrays of commands. */
482 for (temp_list = cmd_list; temp_list; temp_list = temp_list->next) {
483 struct cmd_set *temp_set = temp_list->cmd_set;
485 while (temp_set->name) {
486 if (strequal(argv[0], temp_set->name)) {
487 if (!(temp_set->returntype == RPC_RTYPE_NTSTATUS && temp_set->ntfn ) &&
488 !(temp_set->returntype == RPC_RTYPE_WERROR && temp_set->wfn )) {
489 fprintf (stderr, "Invalid command\n");
493 result = do_cmd(cli, temp_set, argc, argv);
502 printf("command not found: %s\n", argv[0]);
507 if (!NT_STATUS_IS_OK(result)) {
508 printf("result was %s\n", nt_errstr(result));
513 /* NOTE: popt allocates the whole argv, including the
514 * strings, as a single block. So a single free is
515 * enough to release it -- we don't free the
516 * individual strings. rtfm. */
526 int main(int argc, char *argv[])
528 BOOL interactive = True;
530 static char *cmdstr = NULL;
532 struct cli_state *cli;
533 static char *opt_ipaddr=NULL;
534 struct cmd_set **cmd_set;
535 struct in_addr server_ip;
538 /* make sure the vars that get altered (4th field) are in
539 a fixed location or certain compilers complain */
541 struct poptOption long_options[] = {
543 {"command", 'c', POPT_ARG_STRING, &cmdstr, 'c', "Execute semicolon separated cmds", "COMMANDS"},
544 {"dest-ip", 'I', POPT_ARG_STRING, &opt_ipaddr, 'I', "Specify destination IP address", "IP"},
546 POPT_COMMON_CONNECTION
547 POPT_COMMON_CREDENTIALS
551 ZERO_STRUCT(server_ip);
555 /* the following functions are part of the Samba debugging
556 facilities. See lib/debug.c */
557 setup_logging("rpcclient", interactive);
561 /* Load smb.conf file */
563 if (!lp_load(dyn_CONFIGFILE,True,False,False))
564 fprintf(stderr, "Can't load %s\n", dyn_CONFIGFILE);
568 pc = poptGetContext("rpcclient", argc, (const char **) argv,
572 poptPrintHelp(pc, stderr, 0);
576 while((opt = poptGetNextOpt(pc)) != -1) {
580 if ( (server_ip.s_addr=inet_addr(opt_ipaddr)) == INADDR_NONE ) {
581 fprintf(stderr, "%s not a valid IP address\n",
588 /* Get server as remaining unparsed argument. Print usage if more
589 than one unparsed argument is present. */
591 server = poptGetArg(pc);
593 if (!server || poptGetArg(pc)) {
594 poptPrintHelp(pc, stderr, 0);
607 * from stdin if necessary
610 if (!cmdline_auth_info.got_pass) {
611 char *pass = getpass("Password:");
613 pstrcpy(cmdline_auth_info.password, pass);
617 nt_status = cli_full_connection(&cli, global_myname(), server,
618 opt_ipaddr ? &server_ip : NULL, 0,
620 cmdline_auth_info.username, lp_workgroup(),
621 cmdline_auth_info.password, 0, NULL);
623 if (!NT_STATUS_IS_OK(nt_status)) {
624 DEBUG(0,("Cannot connect to server. Error was %s\n", nt_errstr(nt_status)));
628 memset(cmdline_auth_info.password,'X',sizeof(cmdline_auth_info.password));
630 /* Load command lists */
632 cmd_set = rpcclient_command_list;
635 add_command_set(*cmd_set);
636 add_command_set(separator_command);
640 fetch_machine_sid(cli);
642 /* Do anything specified with -c */
643 if (cmdstr && cmdstr[0]) {
648 while((cmd=next_command(&p)) != NULL) {
649 NTSTATUS cmd_result = process_cmd(cli, cmd);
650 result = NT_STATUS_IS_ERR(cmd_result);
657 /* Loop around accepting commands */
663 slprintf(prompt, sizeof(prompt) - 1, "rpcclient $> ");
665 line = smb_readline(prompt, NULL, completion_fn);
671 process_cmd(cli, line);