r24667: Finally merge the registry improvements that Wilco Baan Hofman and I have
[sfrench/samba-autobuild/.git] / source4 / lib / registry / tools / regshell.c
index 6de8b25c9cf66e43454a7f4b0fe157706b66f5e1..0887bc91f3d0304f3147a34d0c6ae1bc62ecab3d 100644 (file)
@@ -2,11 +2,11 @@
    Unix SMB/CIFS implementation.
    simple registry frontend
    
-   Copyright (C) Jelmer Vernooij 2004
+   Copyright (C) Jelmer Vernooij 2004-2007
 
    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,
    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 <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
-#include "dynconfig.h"
-#include "registry.h"
+#include "lib/registry/registry.h"
 #include "lib/cmdline/popt_common.h"
+#include "lib/events/events.h"
 #include "system/time.h"
+#include "lib/smbreadline/smbreadline.h"
+#include "librpc/gen_ndr/ndr_security.h"
+#include "lib/registry/tools/common.h"
+
+struct regshell_context {
+       struct registry_context *registry;
+       const char *path;
+       struct registry_key *current;
+};
 
-/* 
+/* *
  * ck/cd - change key
  * ls - list values/keys
  * rmval/rm - remove value
  * mkkey/mkdir - make key
  * ch - change hive
  * info - show key info
+ * save - save hive
+ * print - print value
  * help
  * exit
  */
 
-static struct registry_key *cmd_info(TALLOC_CTX *mem_ctx, struct registry_key *cur, int argc, char **argv)
+static WERROR cmd_info(struct regshell_context *ctx, int argc, char **argv)
 {
+       struct security_descriptor *sec_desc = NULL;
        time_t last_mod;
-       printf("Name: %s\n", cur->name);
-       printf("Full path: %s\n", cur->path);
-       printf("Key Class: %s\n", cur->class_name);
-       last_mod = nt_time_to_unix(cur->last_mod);
+       WERROR error;
+       const char *classname;
+       NTTIME last_change;
+
+       error = reg_key_get_info(ctx, ctx->current, &classname, NULL, NULL, &last_change);
+       if (!W_ERROR_IS_OK(error)) {
+               printf("Error getting key info: %s\n", win_errstr(error));
+               return error;
+       }
+
+       
+       printf("Name: %s\n", strchr(ctx->path, '\\')?strrchr(ctx->path, '\\')+1: 
+                  ctx->path);
+       printf("Full path: %s\n", ctx->path);
+       printf("Key Class: %s\n", classname);
+       last_mod = nt_time_to_unix(last_change);
        printf("Time Last Modified: %s\n", ctime(&last_mod));
-       /* FIXME: Security info */
-       return cur;
+
+       error = reg_get_sec_desc(ctx, ctx->current, &sec_desc);
+       if (!W_ERROR_IS_OK(error)) {
+               printf("Error getting security descriptor\n");
+               return error;
+       } 
+       ndr_print_debug((ndr_print_fn_t)ndr_print_security_descriptor, "Security", sec_desc);
+       talloc_free(sec_desc);
+
+       return WERR_OK;
 }
 
-static struct registry_key *cmd_pwd(TALLOC_CTX *mem_ctx, struct registry_key *cur, int argc, char **argv)
+static WERROR cmd_predef(struct regshell_context *ctx, int argc, char **argv)
 {
-       printf("%s\n", cur->path);
-       return cur;
+       struct registry_key *ret = NULL;
+       if (argc < 2) {
+               fprintf(stderr, "Usage: predef predefined-key-name\n");
+       } else if (!ctx) {
+               fprintf(stderr, "No full registry loaded, no predefined keys defined\n");
+       } else {
+               WERROR error = reg_get_predefined_key_by_name(ctx->registry, argv[1], &ret);
+
+               if (!W_ERROR_IS_OK(error)) {
+                       fprintf(stderr, "Error opening predefined key %s: %s\n", argv[1], win_errstr(error));
+                       return error;
+               }
+       }
+
+       return WERR_OK;
 }
 
-static struct registry_key *cmd_set(TALLOC_CTX *mem_ctx, struct registry_key *cur, int argc, char **argv)
+static WERROR cmd_pwd(struct regshell_context *ctx,
+                                                                       int argc, char **argv)
 {
-       /* FIXME */
-       return NULL;
+       printf("%s\n", ctx->path);
+       return WERR_OK;
 }
 
-static struct registry_key *cmd_ck(TALLOC_CTX *mem_ctx, struct registry_key *cur, int argc, char **argv)
+static WERROR cmd_set(struct regshell_context *ctx, int argc, char **argv)
+{
+       struct registry_value val;
+       WERROR error;
+
+       if (argc < 4) {
+               fprintf(stderr, "Usage: set value-name type value\n");
+               return WERR_INVALID_PARAM;
+       } 
+
+       if (!reg_string_to_val(ctx, argv[2], argv[3], &val.data_type, 
+                                                  &val.data)) {
+               fprintf(stderr, "Unable to interpret data\n");
+               return WERR_INVALID_PARAM;
+       }
+
+       error = reg_val_set(ctx->current, argv[1], val.data_type, val.data);
+       if (!W_ERROR_IS_OK(error)) {
+               fprintf(stderr, "Error setting value: %s\n", win_errstr(error));
+               return error;
+       }
+
+       return WERR_OK;
+}
+
+static WERROR cmd_ck(struct regshell_context *ctx, int argc, char **argv)
 { 
        struct registry_key *new = NULL;
        WERROR error;
+
        if(argc < 2) {
-               new = cur;
+               new = ctx->current;
        } else {
-               error = reg_open_key(mem_ctx, cur, argv[1], &new);
+               error = reg_open_key(ctx->registry, ctx->current, argv[1], &new);
                if(!W_ERROR_IS_OK(error)) {
                        DEBUG(0, ("Error opening specified key: %s\n", win_errstr(error)));
-                       return NULL;
+                       return error;
                }
        } 
 
-       printf("Current path is: %s\n", new->path);
+       ctx->path = talloc_asprintf(ctx, "%s\\%s", ctx->path, argv[1]);
+       printf("Current path is: %s\n", ctx->path);
+       ctx->current = new;
        
-       return new;
+       return WERR_OK;
+}
+
+static WERROR cmd_print(struct regshell_context *ctx, int argc, char **argv)
+{
+       uint32_t value_type;
+       DATA_BLOB value_data;
+       WERROR error;
+
+       if (argc != 2) {
+               fprintf(stderr, "Usage: print <valuename>");
+               return WERR_INVALID_PARAM;
+       }
+       
+       error = reg_key_get_value_by_name(ctx, ctx->current, argv[1], 
+                                                                         &value_type, &value_data);
+       if (!W_ERROR_IS_OK(error)) {
+               fprintf(stderr, "No such value '%s'\n", argv[1]);
+               return error;
+       }
+
+       printf("%s\n%s\n", str_regtype(value_type), 
+                  reg_val_data_string(ctx, value_type, value_data));
+
+       return WERR_OK;
 }
 
-static struct registry_key *cmd_ls(TALLOC_CTX *mem_ctx, struct registry_key *cur, int argc, char **argv)
+static WERROR cmd_ls(struct regshell_context *ctx, int argc, char **argv)
 {
        int i;
        WERROR error;
        struct registry_value *value;
-       struct registry_key *sub;
-       for(i = 0; W_ERROR_IS_OK(error = reg_key_get_subkey_by_index(mem_ctx, cur, i, &sub)); i++) {
-               printf("K %s\n", sub->name);
+       uint32_t data_type;
+       DATA_BLOB data;
+       const char *name;
+
+       for (i = 0; W_ERROR_IS_OK(error = reg_key_get_subkey_by_index(ctx, ctx->current, i, &name, NULL, NULL)); i++) {
+               printf("K %s\n", name);
        }
 
-       if(!W_ERROR_EQUAL(error, WERR_NO_MORE_ITEMS)) {
+       if (!W_ERROR_EQUAL(error, WERR_NO_MORE_ITEMS)) {
                DEBUG(0, ("Error occured while browsing thru keys: %s\n", win_errstr(error)));
        }
 
-       for(i = 0; W_ERROR_IS_OK(error = reg_key_get_value_by_index(mem_ctx, cur, i, &value)); i++) {
-               printf("V \"%s\" %s %s\n", value->name, str_regtype(value->data_type), reg_val_data_string(mem_ctx, value));
+       for (i = 0; W_ERROR_IS_OK(error = reg_key_get_value_by_index(ctx, ctx->current, i, &name, &data_type, &data)); i++) {
+               printf("V \"%s\" %s %s\n", value->name, str_regtype(data_type), 
+                          reg_val_data_string(ctx, data_type, data));
        }
        
-       return NULL
+       return WERR_OK
 }
-static struct registry_key *cmd_mkkey(TALLOC_CTX *mem_ctx, struct registry_key *cur, int argc, char **argv)
+static WERROR cmd_mkkey(struct regshell_context *ctx, int argc, char **argv)
 { 
        struct registry_key *tmp;
+       WERROR error;
+
        if(argc < 2) {
                fprintf(stderr, "Usage: mkkey <keyname>\n");
-               return NULL;
+               return WERR_INVALID_PARAM;
        }
+
+       error = reg_key_add_name(ctx, ctx->current, argv[1], 0, NULL, &tmp);
        
-       if(!W_ERROR_IS_OK(reg_key_add_name(mem_ctx, cur, argv[1], 0, NULL, &tmp))) {
+       if (!W_ERROR_IS_OK(error)) {
                fprintf(stderr, "Error adding new subkey '%s'\n", argv[1]);
-               return NULL;
+               return error;
        }
 
-       fprintf(stderr, "Successfully added new subkey '%s' to '%s'\n", argv[1], cur->path);
-       
-       return NULL; 
+       return WERR_OK; 
 }
 
-static struct registry_key *cmd_rmkey(TALLOC_CTX *mem_ctx, struct registry_key *cur, int argc, char **argv)
+static WERROR cmd_rmkey(struct regshell_context *ctx,
+                                                                         int argc, char **argv)
 { 
+       WERROR error;
+
        if(argc < 2) {
                fprintf(stderr, "Usage: rmkey <name>\n");
-               return NULL;
+               return WERR_INVALID_PARAM;
        }
 
-       if(!W_ERROR_IS_OK(reg_key_del(cur, argv[1]))) {
+       error = reg_key_del(ctx->current, argv[1]);
+       if(!W_ERROR_IS_OK(error)) {
                fprintf(stderr, "Error deleting '%s'\n", argv[1]);
+               return error;
        } else {
                fprintf(stderr, "Successfully deleted '%s'\n", argv[1]);
        }
        
-       return NULL; 
+       return WERR_OK;
 }
 
-static struct registry_key *cmd_rmval(TALLOC_CTX *mem_ctx, struct registry_key *cur, int argc, char **argv)
+static WERROR cmd_rmval(struct regshell_context *ctx, int argc, char **argv)
 { 
+       WERROR error;
+
        if(argc < 2) {
                fprintf(stderr, "Usage: rmval <valuename>\n");
-               return NULL;
+               return WERR_INVALID_PARAM;
        }
 
-       if(!W_ERROR_IS_OK(reg_del_value(cur, argv[1]))) {
+       error = reg_del_value(ctx->current, argv[1]);
+       if(!W_ERROR_IS_OK(error)) {
                fprintf(stderr, "Error deleting value '%s'\n", argv[1]);
+               return error;
        } else {
                fprintf(stderr, "Successfully deleted value '%s'\n", argv[1]);
        }
 
-       return NULL
+       return WERR_OK
 }
 
-static struct registry_key *cmd_exit(TALLOC_CTX *mem_ctx, struct registry_key *cur, int argc, char **argv)
+static WERROR cmd_exit(struct regshell_context *ctx,
+                                                                        int argc, char **argv)
 {
        exit(0);
-       return NULL; 
+       return WERR_OK;
 }
 
-static struct registry_key *cmd_help(TALLOC_CTX *mem_ctx, struct registry_key *, int, char **);
+static WERROR cmd_help(struct regshell_context *ctx, int, char **);
 
-struct {
+static struct {
        const char *name;
        const char *alias;
        const char *help;
-       struct registry_key *(*handle)(TALLOC_CTX *mem_ctx, struct registry_key *, int argc, char **argv);
+       WERROR (*handle)(struct regshell_context *ctx,
+                                                                  int argc, char **argv);
 } regshell_cmds[] = {
        {"ck", "cd", "Change current key", cmd_ck },
        {"info", "i", "Show detailed information of a key", cmd_info },
        {"list", "ls", "List values/keys in current key", cmd_ls },
+       {"print", "p", "Print value", cmd_print },
        {"mkkey", "mkdir", "Make new key", cmd_mkkey },
        {"rmval", "rm", "Remove value", cmd_rmval },
        {"rmkey", "rmdir", "Remove key", cmd_rmkey },
@@ -174,20 +289,23 @@ struct {
        {"set", "update", "Update value", cmd_set },
        {"help", "?", "Help", cmd_help },
        {"exit", "quit", "Exit", cmd_exit },
+       {"predef", "predefined", "Go to predefined key", cmd_predef },
        {NULL }
 };
 
-static struct registry_key *cmd_help(TALLOC_CTX *mem_ctx, struct registry_key *cur, int argc, char **argv)
+static WERROR cmd_help(struct regshell_context *ctx,
+                                                                        int argc, char **argv)
 {
        int i;
        printf("Available commands:\n");
        for(i = 0; regshell_cmds[i].name; i++) {
                printf("%s - %s\n", regshell_cmds[i].name, regshell_cmds[i].help);
        }
-       return NULL;
+       return WERR_OK;
 } 
 
-static struct registry_key *process_cmd(TALLOC_CTX *mem_ctx, struct registry_key *k, char *line)
+static WERROR process_cmd(struct regshell_context *ctx,
+                                                                               char *line)
 {
        int argc;
        char **argv = NULL;
@@ -195,26 +313,26 @@ static struct registry_key *process_cmd(TALLOC_CTX *mem_ctx, struct registry_key
 
        if ((ret = poptParseArgvString(line, &argc, (const char ***) &argv)) != 0) {
                fprintf(stderr, "regshell: %s\n", poptStrerror(ret));
-               return k;
+               return WERR_INVALID_PARAM;
        }
 
        for(i = 0; regshell_cmds[i].name; i++) {
                if(!strcmp(regshell_cmds[i].name, argv[0]) || 
                   (regshell_cmds[i].alias && !strcmp(regshell_cmds[i].alias, argv[0]))) {
-                       return regshell_cmds[i].handle(mem_ctx, k, argc, argv);
+                       return regshell_cmds[i].handle(ctx, argc, argv);
                }
        }
 
        fprintf(stderr, "No such command '%s'\n", argv[0]);
        
-       return k;
+       return WERR_INVALID_PARAM;
 }
 
 #define MAX_COMPLETIONS 100
 
 static struct registry_key *current_key = NULL;
 
-static char **reg_complete_command(const char *text, int end)
+static char **reg_complete_command(const char *text, int start, int end)
 {
        /* Complete command */
        char **matches;
@@ -262,26 +380,32 @@ cleanup:
        return NULL;
 }
 
-static char **reg_complete_key(const char *text, int end)
+static char **reg_complete_key(const char *text, int start, int end)
 {
-       struct registry_key *subkey;
+       struct registry_key *base;
+       const char *subkeyname;
        int i, j = 1;
        int samelen = 0;
        int len;
        char **matches;
+       const char *base_n = "";
        TALLOC_CTX *mem_ctx;
+       WERROR status;
 
        matches = malloc_array_p(char *, MAX_COMPLETIONS);
        if (!matches) return NULL;
        matches[0] = NULL;
+       mem_ctx = talloc_init("completion");
+
+       base = current_key;
 
        len = strlen(text);
-       mem_ctx = talloc_init("completion");
        for(i = 0; j < MAX_COMPLETIONS-1; i++) {
-               WERROR status = reg_key_get_subkey_by_index(mem_ctx, current_key, i, &subkey);
+               status = reg_key_get_subkey_by_index(mem_ctx, base, i, &subkeyname, 
+                                                                                        NULL, NULL);
                if(W_ERROR_IS_OK(status)) {
-                       if(!strncmp(text, subkey->name, len)) {
-                               matches[j] = strdup(subkey->name);
+                       if(!strncmp(text, subkeyname, len)) {
+                               matches[j] = strdup(subkeyname);
                                j++;
 
                                if (j == 1)
@@ -294,22 +418,24 @@ static char **reg_complete_key(const char *text, int end)
                        break;
                } else {
                        printf("Error creating completion list: %s\n", win_errstr(status));
-                       talloc_destroy(mem_ctx);
+                       talloc_free(mem_ctx);
                        return NULL;
                }
        }
-       talloc_destroy(mem_ctx);
 
        if (j == 1) { /* No matches at all */
                SAFE_FREE(matches);
+               talloc_free(mem_ctx);
                return NULL;
        }
 
        if (j == 2) { /* Exact match */
-               matches[0] = strdup(matches[1]);
+               asprintf(&matches[0], "%s%s", base_n, matches[1]);
        } else {
-               matches[0] = strndup(matches[1], samelen);
+               asprintf(&matches[0], "%s%s", base_n, 
+                               talloc_strndup(mem_ctx, matches[1], samelen));
        }               
+       talloc_free(mem_ctx);
 
        matches[j] = NULL;
        return matches;
@@ -320,86 +446,91 @@ static char **reg_completion(const char *text, int start, int end)
        smb_readline_ca_char(' ');
 
        if (start == 0) {
-               return reg_complete_command(text, end);
+               return reg_complete_command(text, start, end);
        } else {
-               return reg_complete_key(text, end);
+               return reg_complete_key(text, start, end);
        }
 }
 
- int main(int argc, char **argv)
+int main(int argc, char **argv)
 {
        int opt;
-       const char *backend = NULL;
-       struct registry_key *curkey = NULL;
+       const char *file = NULL;
        poptContext pc;
-       WERROR error;
-       TALLOC_CTX *mem_ctx = talloc_init("cmd");
        const char *remote = NULL;
-       struct registry_context *h = NULL;
+       struct regshell_context *ctx;
+       bool ret = true;
        struct poptOption long_options[] = {
                POPT_AUTOHELP
-               POPT_COMMON_CREDENTIALS
-               {"backend", 'b', POPT_ARG_STRING, &backend, 0, "backend to use", NULL},
+               {"file", 'F', POPT_ARG_STRING, &file, 0, "open hive file", NULL },
                {"remote", 'R', POPT_ARG_STRING, &remote, 0, "connect to specified remote server", NULL},
-               POPT_TABLEEND
+               POPT_COMMON_SAMBA
+               POPT_COMMON_CREDENTIALS
+               POPT_COMMON_VERSION
+               { NULL }
        };
 
-       regshell_init_subsystems;
-
-       if (!lp_load(dyn_CONFIGFILE,True,False,False)) {
-               fprintf(stderr, "Can't load %s - run testparm to debug it\n", dyn_CONFIGFILE);
-       }
-
-       
        pc = poptGetContext(argv[0], argc, (const char **) argv, long_options,0);
        
        while((opt = poptGetNextOpt(pc)) != -1) {
        }
 
-    setup_logging("regtree", True);
+       ctx = talloc_zero(NULL, struct regshell_context);
 
-       if (remote) {
-               error = reg_open_remote (&h, cmdline_get_username(), cmdline_get_userpassword(), remote); 
-       } else if (backend) {
-               error = reg_open_hive(NULL, backend, poptGetArg(pc), NULL, &curkey);
+       if (remote != NULL) {
+               ctx->registry = reg_common_open_remote(remote, cmdline_credentials);
+       } else if (file != NULL) {
+               ctx->current = reg_common_open_file(file, cmdline_credentials);
+               ctx->registry = ctx->current->context;
+               ctx->path = talloc_strdup(ctx, "");
        } else {
-               error = reg_open_local(&h);
+               ctx->registry = reg_common_open_local(cmdline_credentials);
        }
 
-       if(!W_ERROR_IS_OK(error)) {
-               fprintf(stderr, "Unable to open registry\n");
+       if (ctx->registry == NULL)
                return 1;
+
+       if (ctx->current == NULL) {
+               int i;
+
+               for (i = 0; reg_predefined_keys[i].handle; i++) {
+                       WERROR err;
+                       err = reg_get_predefined_key(ctx->registry, 
+                                                                                reg_predefined_keys[i].handle, 
+                                                                                &ctx->current);
+                       if (W_ERROR_IS_OK(err)) {
+                               ctx->path = talloc_strdup(ctx, reg_predefined_keys[i].name);
+                               break;
+                       } else {
+                               ctx->current = NULL;
+                       }
+               }
        }
 
-       if (h) {
-               /*FIXME: What if HKEY_CLASSES_ROOT is not present ? */
-               reg_get_predefined_key(h, HKEY_CLASSES_ROOT, &curkey);
+       if (ctx->current == NULL) {
+               fprintf(stderr, "Unable to access any of the predefined keys\n");
+               return -1;
        }
        
        poptFreeContext(pc);
        
-       while(True) {
+       while (true) {
                char *line, *prompt;
                
-               if(curkey->hive->root->name) {
-                       asprintf(&prompt, "%s:%s> ", curkey->hive->root->name, curkey->path);
-               } else {
-                       asprintf(&prompt, "%s> ", curkey->path);
-               }
+               asprintf(&prompt, "%s> ", ctx->path);
                
-               current_key = curkey;           /* No way to pass a void * pointer 
-                                                                          via readline :-( */
+               current_key = ctx->current;             /* No way to pass a void * pointer 
+                                                                                          via readline :-( */
                line = smb_readline(prompt, NULL, reg_completion);
 
-               if(!line)
+               if (line == NULL)
                        break;
 
-               if(line[0] != '\n') {
-                       struct registry_key *new = process_cmd(mem_ctx, curkey, line);
-                       if(new)curkey = new;
+               if (line[0] != '\n') {
+                       ret = W_ERROR_IS_OK(process_cmd(ctx, line));
                }
        }
-       talloc_destroy(mem_ctx);
+       talloc_free(ctx);
 
-       return 0;
+       return (ret?0:1);
 }