From 541ed81a630aeae97a178e9099b0a920f9b3f84f Mon Sep 17 00:00:00 2001 From: Martin Pool Date: Mon, 17 Feb 2003 05:42:36 +0000 Subject: [PATCH] Start reworking rpcclient to use popt rather than next_token to parse command lines. This makes the code much simpler and also stops trivial syntax errors from causing a crash. Also fix support for semicolon-separated commands in -c, which is promised by the manual but apparently never working due to an off-by-one error. (This used to be commit d85a25e733fe970ae96a02a5cbc892f2b8dca1b7) --- source3/rpcclient/rpcclient.c | 174 ++++++++++++++-------------------- 1 file changed, 70 insertions(+), 104 deletions(-) diff --git a/source3/rpcclient/rpcclient.c b/source3/rpcclient/rpcclient.c index 2609519dc48..f38ef64eb2a 100644 --- a/source3/rpcclient/rpcclient.c +++ b/source3/rpcclient/rpcclient.c @@ -3,6 +3,7 @@ RPC pipe client Copyright (C) Tim Potter 2000-2001 + Copyright (C) Martin Pool 2003 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 @@ -24,7 +25,12 @@ DOM_SID domain_sid; -/* List to hold groups of commands */ + +/* List to hold groups of commands. + * + * Commands are defined in a list of arrays: arrays are easy to + * statically declare, and lists are easier to dynamically extend. + */ static struct cmd_list { struct cmd_list *prev, *next; @@ -164,7 +170,7 @@ static char* next_command (char** cmdstr) if (p) *p = '\0'; pstrcpy(command, *cmdstr); - *cmdstr = p; + *cmdstr = p + 1; return command; } @@ -371,7 +377,7 @@ static NTSTATUS cmd_quit(struct cli_state *cli, TALLOC_CTX *mem_ctx, return NT_STATUS_OK; /* NOTREACHED */ } -/* Build in rpcclient commands */ +/* Built in rpcclient commands */ static struct cmd_set rpcclient_commands[] = { @@ -432,145 +438,105 @@ static void add_command_set(struct cmd_set *cmd_set) DLIST_ADD(cmd_list, entry); } -static NTSTATUS do_cmd(struct cli_state *cli, struct cmd_set *cmd_entry, - char *cmd) + +/** + * Call an rpcclient function, passing an argv array. + * + * @param cmd Command to run, as a single string. + **/ +static NTSTATUS do_cmd(struct cli_state *cli, + struct cmd_set *cmd_entry, + int argc, char **argv) { - char **argv = NULL; - const char *p = cmd; - NTSTATUS result = NT_STATUS_UNSUCCESSFUL; - pstring buf; - int argc = 0, i; + NTSTATUS result; + + TALLOC_CTX *mem_ctx; - /* Count number of arguments first time through the loop then - allocate memory and strdup them. */ + /* Create mem_ctx */ - again: - while(next_token(&p, buf, " ", sizeof(buf))) { - if (argv) { - argv[argc] = strdup(buf); - } - - argc++; - } - - if (!argv) { - - /* Create argument list */ - - argv = (char **)malloc(sizeof(char *) * argc); - memset(argv, 0, sizeof(char *) * argc); - - if (!argv) { - fprintf(stderr, "out of memory\n"); - result = NT_STATUS_NO_MEMORY; - goto done; - } - - p = cmd; - argc = 0; - - goto again; + if (!(mem_ctx = talloc_init("do_cmd"))) { + DEBUG(0, ("talloc_init() failed\n")); + return NT_STATUS_UNSUCCESSFUL; } - /* Call the function */ + /* Open pipe */ - if (cmd_entry->fn) { - TALLOC_CTX *mem_ctx; + if (cmd_entry->pipe_idx != -1) + if (!cli_nt_session_open(cli, cmd_entry->pipe_idx)) { + DEBUG(0, ("Could not initialize pipe\n")); + return NT_STATUS_UNSUCCESSFUL; + } - /* Create mem_ctx */ + /* Run command */ - if (!(mem_ctx = talloc_init("do_cmd"))) { - DEBUG(0, ("talloc_init() failed\n")); - goto done; - } + result = cmd_entry->fn(cli, mem_ctx, argc, (char **) argv); - /* Open pipe */ - - if (cmd_entry->pipe_idx != -1) - if (!cli_nt_session_open(cli, cmd_entry->pipe_idx)) { - DEBUG(0, ("Could not initialise pipe\n")); - goto done; - } - - /* Run command */ - - result = cmd_entry->fn(cli, mem_ctx, argc, argv); - - /* Cleanup */ - - if (cmd_entry->pipe_idx != -1) - cli_nt_session_close(cli); - - talloc_destroy(mem_ctx); - - } else { - fprintf (stderr, "Invalid command\n"); - goto done; - } - - done: - /* Cleanup */ - if (argv) { - for (i = 0; i < argc; i++) - SAFE_FREE(argv[i]); - - SAFE_FREE(argv); - } - + if (cmd_entry->pipe_idx != -1) + cli_nt_session_close(cli); + + talloc_destroy(mem_ctx); + return result; } -/* Process a command entered at the prompt or as part of -c */ +/** + * Process a command entered at the prompt or as part of -c + * + * @returns The NTSTATUS from running the command. + **/ static NTSTATUS process_cmd(struct cli_state *cli, char *cmd) { struct cmd_list *temp_list; - BOOL found = False; - pstring buf; - const char *p = cmd; NTSTATUS result = NT_STATUS_OK; - int len = 0; + int ret; + int argc; + char **argv = NULL; - if (cmd[strlen(cmd) - 1] == '\n') - cmd[strlen(cmd) - 1] = '\0'; - - if (!next_token(&p, buf, " ", sizeof(buf))) { - return NT_STATUS_OK; + if ((ret = poptParseArgvString(cmd, &argc, (const char ***) &argv)) != 0) { + fprintf(stderr, "rpcclient: %s\n", poptStrerror(ret)); + return NT_STATUS_UNSUCCESSFUL; } - /* strip the trainly \n if it exsists */ - len = strlen(buf); - if (buf[len-1] == '\n') - buf[len-1] = '\0'; - - /* Search for matching commands */ + /* Walk through a dlist of arrays of commands. */ for (temp_list = cmd_list; temp_list; temp_list = temp_list->next) { struct cmd_set *temp_set = temp_list->cmd_set; - while(temp_set->name) { - if (strequal(buf, temp_set->name)) { - found = True; - result = do_cmd(cli, temp_set, cmd); + while (temp_set->name) { + if (strequal(argv[0], temp_set->name)) { + if (!temp_set->fn) { + fprintf (stderr, "Invalid command\n"); + goto out_free; + } - goto done; + result = do_cmd(cli, temp_set, argc, argv); + + goto out_free; } temp_set++; } } - done: - if (!found && buf[0]) { - printf("command not found: %s\n", buf); - return NT_STATUS_OK; + if (argv[0]) { + printf("command not found: %s\n", argv[0]); } +out_free: if (!NT_STATUS_IS_OK(result)) { printf("result was %s\n", nt_errstr(result)); } + 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); + } + return result; }