1
0
mirror of https://github.com/samba-team/samba.git synced 2025-12-14 20:23:54 +03:00
Files
samba-mirror/source/lib/registry/tools/regshell.c
Andrew Bartlett 50f3c2b3a2 r7525: Unify lp_load(), load_interfaces and logging setup into popt().
There is now a new --debug-stderr option to enable debug to STDERR.

popt isn't perfect, but the callbacks are used in all the main Samba
binaries, and should be used in the rest.  This avoids duplicated
code, and ensures every binary is setup correctly.

This also ensures the setup happens early enough to have -s function,
and have a correct impact on the credentials code.  (Fixing a bug that
frustrated tridge earlier today).

The only 'subtle' aspect of all this is that I'm pretty sure that the
SAMBA_COMMON popt code must be above the CREDENTIALS code, in the
popt tables.

Andrew Bartlett
2007-10-10 13:18:06 -05:00

463 lines
12 KiB
C

/*
Unix SMB/CIFS implementation.
simple registry frontend
Copyright (C) Jelmer Vernooij 2004
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
(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, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
#include "dynconfig.h"
#include "registry.h"
#include "lib/cmdline/popt_common.h"
#include "system/time.h"
/*
* ck/cd - change key
* ls - list values/keys
* rmval/rm - remove value
* rmkey/rmdir - remove key
* mkkey/mkdir - make key
* ch - change hive
* info - show key info
* help
* exit
*/
static struct registry_key *cmd_info(TALLOC_CTX *mem_ctx, struct registry_context *ctx,struct registry_key *cur, int argc, char **argv)
{
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);
printf("Time Last Modified: %s\n", ctime(&last_mod));
/* FIXME: Security info */
return cur;
}
static struct registry_key *cmd_predef(TALLOC_CTX *mem_ctx, struct registry_context *ctx, struct registry_key *cur, int argc, char **argv)
{
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, argv[1], &ret);
if (!W_ERROR_IS_OK(error)) {
fprintf(stderr, "Error opening predefined key %s: %s\n", argv[1], win_errstr(error));
ret = NULL;
}
}
return ret;
}
static struct registry_key *cmd_pwd(TALLOC_CTX *mem_ctx, struct registry_context *ctx,struct registry_key *cur, int argc, char **argv)
{
printf("%s\n", cur->path);
return cur;
}
static struct registry_key *cmd_set(TALLOC_CTX *mem_ctx, struct registry_context *ctx,struct registry_key *cur, int argc, char **argv)
{
if (argc < 4) {
fprintf(stderr, "Usage: set value-name type value\n");
} else {
struct registry_value *val;
if (reg_string_to_val(mem_ctx, argv[2], argv[3], &val)) {
WERROR error = reg_val_set(cur, argv[1], val->data_type, val->data_blk, val->data_len);
if (!W_ERROR_IS_OK(error)) {
fprintf(stderr, "Error setting value: %s\n", win_errstr(error));
return NULL;
}
} else {
fprintf(stderr, "Unable to interpret data\n");
}
}
return cur;
}
static struct registry_key *cmd_ck(TALLOC_CTX *mem_ctx, struct registry_context *ctx,struct registry_key *cur, int argc, char **argv)
{
struct registry_key *new = NULL;
WERROR error;
if(argc < 2) {
new = cur;
} else {
error = reg_open_key(mem_ctx, cur, argv[1], &new);
if(!W_ERROR_IS_OK(error)) {
DEBUG(0, ("Error opening specified key: %s\n", win_errstr(error)));
return NULL;
}
}
printf("Current path is: %s\n", new->path);
return new;
}
static struct registry_key *cmd_ls(TALLOC_CTX *mem_ctx, struct registry_context *ctx,struct registry_key *cur, 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);
}
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));
}
return NULL;
}
static struct registry_key *cmd_mkkey(TALLOC_CTX *mem_ctx, struct registry_context *ctx,struct registry_key *cur, int argc, char **argv)
{
struct registry_key *tmp;
if(argc < 2) {
fprintf(stderr, "Usage: mkkey <keyname>\n");
return NULL;
}
if(!W_ERROR_IS_OK(reg_key_add_name(mem_ctx, cur, argv[1], 0, NULL, &tmp))) {
fprintf(stderr, "Error adding new subkey '%s'\n", argv[1]);
return NULL;
}
return NULL;
}
static struct registry_key *cmd_rmkey(TALLOC_CTX *mem_ctx, struct registry_context *ctx,struct registry_key *cur, int argc, char **argv)
{
if(argc < 2) {
fprintf(stderr, "Usage: rmkey <name>\n");
return NULL;
}
if(!W_ERROR_IS_OK(reg_key_del(cur, argv[1]))) {
fprintf(stderr, "Error deleting '%s'\n", argv[1]);
} else {
fprintf(stderr, "Successfully deleted '%s'\n", argv[1]);
}
return NULL;
}
static struct registry_key *cmd_rmval(TALLOC_CTX *mem_ctx, struct registry_context *ctx,struct registry_key *cur, int argc, char **argv)
{
if(argc < 2) {
fprintf(stderr, "Usage: rmval <valuename>\n");
return NULL;
}
if(!W_ERROR_IS_OK(reg_del_value(cur, argv[1]))) {
fprintf(stderr, "Error deleting value '%s'\n", argv[1]);
} else {
fprintf(stderr, "Successfully deleted value '%s'\n", argv[1]);
}
return NULL;
}
static struct registry_key *cmd_exit(TALLOC_CTX *mem_ctx, struct registry_context *ctx,struct registry_key *cur, int argc, char **argv)
{
exit(0);
return NULL;
}
static struct registry_key *cmd_help(TALLOC_CTX *mem_ctx, struct registry_context *ctx,struct registry_key *, int, char **);
static struct {
const char *name;
const char *alias;
const char *help;
struct registry_key *(*handle)(TALLOC_CTX *mem_ctx, struct registry_context *ctx,struct registry_key *, 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 },
{"mkkey", "mkdir", "Make new key", cmd_mkkey },
{"rmval", "rm", "Remove value", cmd_rmval },
{"rmkey", "rmdir", "Remove key", cmd_rmkey },
{"pwd", "pwk", "Printing current key", cmd_pwd },
{"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_context *ctx, struct registry_key *cur, 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;
}
static struct registry_key *process_cmd(TALLOC_CTX *mem_ctx, struct registry_context *ctx, struct registry_key *k, char *line)
{
int argc;
char **argv = NULL;
int ret, i;
if ((ret = poptParseArgvString(line, &argc, (const char ***) &argv)) != 0) {
fprintf(stderr, "regshell: %s\n", poptStrerror(ret));
return k;
}
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, ctx, k, argc, argv);
}
}
fprintf(stderr, "No such command '%s'\n", argv[0]);
return k;
}
#define MAX_COMPLETIONS 100
static struct registry_key *current_key = NULL;
static char **reg_complete_command(const char *text, int start, int end)
{
/* Complete command */
char **matches;
int i, len, samelen=0, count=1;
matches = malloc_array_p(char *, MAX_COMPLETIONS);
if (!matches) return NULL;
matches[0] = NULL;
len = strlen(text);
for (i=0;regshell_cmds[i].handle && count < MAX_COMPLETIONS-1;i++) {
if (strncmp(text, regshell_cmds[i].name, len) == 0) {
matches[count] = strdup(regshell_cmds[i].name);
if (!matches[count])
goto cleanup;
if (count == 1)
samelen = strlen(matches[count]);
else
while (strncmp(matches[count], matches[count-1], samelen) != 0)
samelen--;
count++;
}
}
switch (count) {
case 0: /* should never happen */
case 1:
goto cleanup;
case 2:
matches[0] = strdup(matches[1]);
break;
default:
matches[0] = strndup(matches[1], samelen);
}
matches[count] = NULL;
return matches;
cleanup:
count--;
while (count >= 0) {
free(matches[count]);
count--;
}
free(matches);
return NULL;
}
static char **reg_complete_key(const char *text, int start, int end)
{
struct registry_key *base;
struct registry_key *subkey;
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);
for(i = 0; j < MAX_COMPLETIONS-1; i++) {
status = reg_key_get_subkey_by_index(mem_ctx, base, i, &subkey);
if(W_ERROR_IS_OK(status)) {
if(!strncmp(text, subkey->name, len)) {
matches[j] = strdup(subkey->name);
j++;
if (j == 1)
samelen = strlen(matches[j]);
else
while (strncmp(matches[j], matches[j-1], samelen) != 0)
samelen--;
}
} else if(W_ERROR_EQUAL(status, WERR_NO_MORE_ITEMS)) {
break;
} else {
printf("Error creating completion list: %s\n", win_errstr(status));
talloc_free(mem_ctx);
return NULL;
}
}
if (j == 1) { /* No matches at all */
SAFE_FREE(matches);
talloc_free(mem_ctx);
return NULL;
}
if (j == 2) { /* Exact match */
asprintf(&matches[0], "%s%s", base_n, matches[1]);
} else {
asprintf(&matches[0], "%s%s", base_n, talloc_strndup(mem_ctx, matches[1], samelen));
}
talloc_free(mem_ctx);
matches[j] = NULL;
return matches;
}
static char **reg_completion(const char *text, int start, int end)
{
smb_readline_ca_char(' ');
if (start == 0) {
return reg_complete_command(text, start, end);
} else {
return reg_complete_key(text, start, end);
}
}
int main(int argc, char **argv)
{
int opt;
const char *backend = NULL;
struct registry_key *curkey = NULL;
poptContext pc;
WERROR error;
TALLOC_CTX *mem_ctx = talloc_init("cmd");
const char *remote = NULL;
struct registry_context *h = NULL;
struct poptOption long_options[] = {
POPT_AUTOHELP
{"backend", 'b', POPT_ARG_STRING, &backend, 0, "backend to use", NULL},
{"remote", 'R', POPT_ARG_STRING, &remote, 0, "connect to specified remote server", NULL},
POPT_COMMON_SAMBA
POPT_COMMON_CREDENTIALS
POPT_COMMON_VERSION
POPT_TABLEEND
};
regshell_init_subsystems;
pc = poptGetContext(argv[0], argc, (const char **) argv, long_options,0);
while((opt = poptGetNextOpt(pc)) != -1) {
}
if (remote) {
error = reg_open_remote (&h, cmdline_credentials, remote);
} else if (backend) {
error = reg_open_hive(NULL, backend, poptGetArg(pc), NULL, &curkey);
} else {
error = reg_open_local(&h);
}
if(!W_ERROR_IS_OK(error)) {
fprintf(stderr, "Unable to open registry\n");
return 1;
}
if (h) {
uint32_t try_hkeys[] = {
HKEY_CLASSES_ROOT,
HKEY_CURRENT_USER,
HKEY_LOCAL_MACHINE,
HKEY_USERS,
HKEY_PERFORMANCE_DATA,
HKEY_CURRENT_CONFIG,
HKEY_DYN_DATA,
HKEY_PERFORMANCE_TEXT,
HKEY_PERFORMANCE_NLSTEXT,
0
};
int i;
for (i = 0; try_hkeys[i]; i++) {
WERROR err;
err = reg_get_predefined_key(h, try_hkeys[i], &curkey);
if (W_ERROR_IS_OK(err)) {
break;
} else {
curkey = NULL;
}
}
}
if (!curkey) {
fprintf(stderr, "Unable to access any of the predefined keys\n");
return -1;
}
poptFreeContext(pc);
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);
}
current_key = curkey; /* No way to pass a void * pointer
via readline :-( */
line = smb_readline(prompt, NULL, reg_completion);
if(!line)
break;
if(line[0] != '\n') {
struct registry_key *new = process_cmd(mem_ctx, h, curkey, line);
if(new)curkey = new;
}
}
talloc_free(mem_ctx);
return 0;
}