r25603: More reformat.
[ira/wip.git] / source / lib / registry / tools / regshell.c
1 /*
2    Unix SMB/CIFS implementation.
3    simple registry frontend
4
5    Copyright (C) Jelmer Vernooij 2004-2007
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "includes.h"
22 #include "lib/registry/registry.h"
23 #include "lib/cmdline/popt_common.h"
24 #include "lib/events/events.h"
25 #include "system/time.h"
26 #include "lib/smbreadline/smbreadline.h"
27 #include "librpc/gen_ndr/ndr_security.h"
28 #include "lib/registry/tools/common.h"
29
30 struct regshell_context {
31         struct registry_context *registry;
32         const char *path;
33         struct registry_key *current;
34 };
35
36 /* *
37  * ck/cd - change key
38  * ls - list values/keys
39  * rmval/rm - remove value
40  * rmkey/rmdir - remove key
41  * mkkey/mkdir - make key
42  * ch - change hive
43  * info - show key info
44  * save - save hive
45  * print - print value
46  * help
47  * exit
48  */
49
50 static WERROR cmd_info(struct regshell_context *ctx, int argc, char **argv)
51 {
52         struct security_descriptor *sec_desc = NULL;
53         time_t last_mod;
54         WERROR error;
55         const char *classname;
56         NTTIME last_change;
57
58         error = reg_key_get_info(ctx, ctx->current, &classname, NULL, NULL,
59                                  &last_change);
60         if (!W_ERROR_IS_OK(error)) {
61                 printf("Error getting key info: %s\n", win_errstr(error));
62                 return error;
63         }
64
65
66         printf("Name: %s\n", strchr(ctx->path, '\\')?strrchr(ctx->path, '\\')+1:
67                    ctx->path);
68         printf("Full path: %s\n", ctx->path);
69         printf("Key Class: %s\n", classname);
70         last_mod = nt_time_to_unix(last_change);
71         printf("Time Last Modified: %s\n", ctime(&last_mod));
72
73         error = reg_get_sec_desc(ctx, ctx->current, &sec_desc);
74         if (!W_ERROR_IS_OK(error)) {
75                 printf("Error getting security descriptor\n");
76                 return error;
77         }
78         ndr_print_debug((ndr_print_fn_t)ndr_print_security_descriptor,
79                         "Security", sec_desc);
80         talloc_free(sec_desc);
81
82         return WERR_OK;
83 }
84
85 static WERROR cmd_predef(struct regshell_context *ctx, int argc, char **argv)
86 {
87         struct registry_key *ret = NULL;
88         if (argc < 2) {
89                 fprintf(stderr, "Usage: predef predefined-key-name\n");
90         } else if (!ctx) {
91                 fprintf(stderr, "No full registry loaded, no predefined keys defined\n");
92         } else {
93                 WERROR error = reg_get_predefined_key_by_name(ctx->registry,
94                                                               argv[1], &ret);
95
96                 if (!W_ERROR_IS_OK(error)) {
97                         fprintf(stderr, "Error opening predefined key %s: %s\n",
98                                 argv[1], win_errstr(error));
99                         return error;
100                 }
101         }
102
103         return WERR_OK;
104 }
105
106 static WERROR cmd_pwd(struct regshell_context *ctx,
107                       int argc, char **argv)
108 {
109         printf("%s\n", ctx->path);
110         return WERR_OK;
111 }
112
113 static WERROR cmd_set(struct regshell_context *ctx, int argc, char **argv)
114 {
115         struct registry_value val;
116         WERROR error;
117
118         if (argc < 4) {
119                 fprintf(stderr, "Usage: set value-name type value\n");
120                 return WERR_INVALID_PARAM;
121         }
122
123         if (!reg_string_to_val(ctx, argv[2], argv[3], &val.data_type,
124                                &val.data)) {
125                 fprintf(stderr, "Unable to interpret data\n");
126                 return WERR_INVALID_PARAM;
127         }
128
129         error = reg_val_set(ctx->current, argv[1], val.data_type, val.data);
130         if (!W_ERROR_IS_OK(error)) {
131                 fprintf(stderr, "Error setting value: %s\n", win_errstr(error));
132                 return error;
133         }
134
135         return WERR_OK;
136 }
137
138 static WERROR cmd_ck(struct regshell_context *ctx, int argc, char **argv)
139 {
140         struct registry_key *new = NULL;
141         WERROR error;
142
143         if(argc < 2) {
144                 new = ctx->current;
145         } else {
146                 error = reg_open_key(ctx->registry, ctx->current, argv[1],
147                                      &new);
148                 if(!W_ERROR_IS_OK(error)) {
149                         DEBUG(0, ("Error opening specified key: %s\n",
150                                 win_errstr(error)));
151                         return error;
152                 }
153         }
154
155         ctx->path = talloc_asprintf(ctx, "%s\\%s", ctx->path, argv[1]);
156         printf("Current path is: %s\n", ctx->path);
157         ctx->current = new;
158
159         return WERR_OK;
160 }
161
162 static WERROR cmd_print(struct regshell_context *ctx, int argc, char **argv)
163 {
164         uint32_t value_type;
165         DATA_BLOB value_data;
166         WERROR error;
167
168         if (argc != 2) {
169                 fprintf(stderr, "Usage: print <valuename>");
170                 return WERR_INVALID_PARAM;
171         }
172
173         error = reg_key_get_value_by_name(ctx, ctx->current, argv[1],
174                                           &value_type, &value_data);
175         if (!W_ERROR_IS_OK(error)) {
176                 fprintf(stderr, "No such value '%s'\n", argv[1]);
177                 return error;
178         }
179
180         printf("%s\n%s\n", str_regtype(value_type),
181                    reg_val_data_string(ctx, value_type, value_data));
182
183         return WERR_OK;
184 }
185
186 static WERROR cmd_ls(struct regshell_context *ctx, int argc, char **argv)
187 {
188         int i;
189         WERROR error;
190         struct registry_value *value;
191         uint32_t data_type;
192         DATA_BLOB data;
193         const char *name;
194
195         for (i = 0; W_ERROR_IS_OK(error = reg_key_get_subkey_by_index(ctx,
196                                                                       ctx->current,
197                                                                       i,
198                                                                       &name,
199                                                                       NULL,
200                                                                       NULL)); i++) {
201                 printf("K %s\n", name);
202         }
203
204         if (!W_ERROR_EQUAL(error, WERR_NO_MORE_ITEMS)) {
205                 DEBUG(0, ("Error occured while browsing thru keys: %s\n",
206                         win_errstr(error)));
207         }
208
209         for (i = 0; W_ERROR_IS_OK(error = reg_key_get_value_by_index(ctx,
210                                                                      ctx->current,
211                                                                      i,
212                                                                      &name,
213                                                                      &data_type,
214                                                                      &data)); i++) {
215                 printf("V \"%s\" %s %s\n", value->name, str_regtype(data_type),
216                            reg_val_data_string(ctx, data_type, data));
217         }
218
219         return WERR_OK;
220 }
221 static WERROR cmd_mkkey(struct regshell_context *ctx, int argc, char **argv)
222 {
223         struct registry_key *tmp;
224         WERROR error;
225
226         if(argc < 2) {
227                 fprintf(stderr, "Usage: mkkey <keyname>\n");
228                 return WERR_INVALID_PARAM;
229         }
230
231         error = reg_key_add_name(ctx, ctx->current, argv[1], 0, NULL, &tmp);
232
233         if (!W_ERROR_IS_OK(error)) {
234                 fprintf(stderr, "Error adding new subkey '%s'\n", argv[1]);
235                 return error;
236         }
237
238         return WERR_OK;
239 }
240
241 static WERROR cmd_rmkey(struct regshell_context *ctx,
242                         int argc, char **argv)
243 {
244         WERROR error;
245
246         if(argc < 2) {
247                 fprintf(stderr, "Usage: rmkey <name>\n");
248                 return WERR_INVALID_PARAM;
249         }
250
251         error = reg_key_del(ctx->current, argv[1]);
252         if(!W_ERROR_IS_OK(error)) {
253                 fprintf(stderr, "Error deleting '%s'\n", argv[1]);
254                 return error;
255         } else {
256                 fprintf(stderr, "Successfully deleted '%s'\n", argv[1]);
257         }
258
259         return WERR_OK;
260 }
261
262 static WERROR cmd_rmval(struct regshell_context *ctx, int argc, char **argv)
263 {
264         WERROR error;
265
266         if(argc < 2) {
267                 fprintf(stderr, "Usage: rmval <valuename>\n");
268                 return WERR_INVALID_PARAM;
269         }
270
271         error = reg_del_value(ctx->current, argv[1]);
272         if(!W_ERROR_IS_OK(error)) {
273                 fprintf(stderr, "Error deleting value '%s'\n", argv[1]);
274                 return error;
275         } else {
276                 fprintf(stderr, "Successfully deleted value '%s'\n", argv[1]);
277         }
278
279         return WERR_OK;
280 }
281
282 _NORETURN_ static WERROR cmd_exit(struct regshell_context *ctx,
283                                   int argc, char **argv)
284 {
285         exit(0);
286         return WERR_OK;
287 }
288
289 static WERROR cmd_help(struct regshell_context *ctx, int, char **);
290
291 static struct {
292         const char *name;
293         const char *alias;
294         const char *help;
295         WERROR (*handle)(struct regshell_context *ctx, int argc, char **argv);
296 } regshell_cmds[] = {
297         {"ck", "cd", "Change current key", cmd_ck },
298         {"info", "i", "Show detailed information of a key", cmd_info },
299         {"list", "ls", "List values/keys in current key", cmd_ls },
300         {"print", "p", "Print value", cmd_print },
301         {"mkkey", "mkdir", "Make new key", cmd_mkkey },
302         {"rmval", "rm", "Remove value", cmd_rmval },
303         {"rmkey", "rmdir", "Remove key", cmd_rmkey },
304         {"pwd", "pwk", "Printing current key", cmd_pwd },
305         {"set", "update", "Update value", cmd_set },
306         {"help", "?", "Help", cmd_help },
307         {"exit", "quit", "Exit", cmd_exit },
308         {"predef", "predefined", "Go to predefined key", cmd_predef },
309         {NULL }
310 };
311
312 static WERROR cmd_help(struct regshell_context *ctx,
313                        int argc, char **argv)
314 {
315         int i;
316         printf("Available commands:\n");
317         for(i = 0; regshell_cmds[i].name; i++) {
318                 printf("%s - %s\n", regshell_cmds[i].name,
319                         regshell_cmds[i].help);
320         }
321         return WERR_OK;
322 }
323
324 static WERROR process_cmd(struct regshell_context *ctx,
325                           char *line)
326 {
327         int argc;
328         char **argv = NULL;
329         int ret, i;
330
331         if ((ret = poptParseArgvString(line, &argc, (const char ***) &argv)) != 0) {
332                 fprintf(stderr, "regshell: %s\n", poptStrerror(ret));
333                 return WERR_INVALID_PARAM;
334         }
335
336         for(i = 0; regshell_cmds[i].name; i++) {
337                 if(!strcmp(regshell_cmds[i].name, argv[0]) ||
338                    (regshell_cmds[i].alias && !strcmp(regshell_cmds[i].alias, argv[0]))) {
339                         return regshell_cmds[i].handle(ctx, argc, argv);
340                 }
341         }
342
343         fprintf(stderr, "No such command '%s'\n", argv[0]);
344
345         return WERR_INVALID_PARAM;
346 }
347
348 #define MAX_COMPLETIONS 100
349
350 static struct registry_key *current_key = NULL;
351
352 static char **reg_complete_command(const char *text, int start, int end)
353 {
354         /* Complete command */
355         char **matches;
356         int i, len, samelen=0, count=1;
357
358         matches = malloc_array_p(char *, MAX_COMPLETIONS);
359         if (!matches) return NULL;
360         matches[0] = NULL;
361
362         len = strlen(text);
363         for (i=0;regshell_cmds[i].handle && count < MAX_COMPLETIONS-1;i++) {
364                 if (strncmp(text, regshell_cmds[i].name, len) == 0) {
365                         matches[count] = strdup(regshell_cmds[i].name);
366                         if (!matches[count])
367                                 goto cleanup;
368                         if (count == 1)
369                                 samelen = strlen(matches[count]);
370                         else
371                                 while (strncmp(matches[count], matches[count-1], samelen) != 0)
372                                         samelen--;
373                         count++;
374                 }
375         }
376
377         switch (count) {
378         case 0: /* should never happen */
379         case 1:
380                 goto cleanup;
381         case 2:
382                 matches[0] = strdup(matches[1]);
383                 break;
384         default:
385                 matches[0] = strndup(matches[1], samelen);
386         }
387         matches[count] = NULL;
388         return matches;
389
390 cleanup:
391         count--;
392         while (count >= 0) {
393                 free(matches[count]);
394                 count--;
395         }
396         free(matches);
397         return NULL;
398 }
399
400 static char **reg_complete_key(const char *text, int start, int end)
401 {
402         struct registry_key *base;
403         const char *subkeyname;
404         int i, j = 1;
405         int samelen = 0;
406         int len;
407         char **matches;
408         const char *base_n = "";
409         TALLOC_CTX *mem_ctx;
410         WERROR status;
411
412         matches = malloc_array_p(char *, MAX_COMPLETIONS);
413         if (!matches) return NULL;
414         matches[0] = NULL;
415         mem_ctx = talloc_init("completion");
416
417         base = current_key;
418
419         len = strlen(text);
420         for(i = 0; j < MAX_COMPLETIONS-1; i++) {
421                 status = reg_key_get_subkey_by_index(mem_ctx, base, i,
422                                                      &subkeyname, NULL, NULL);
423                 if(W_ERROR_IS_OK(status)) {
424                         if(!strncmp(text, subkeyname, len)) {
425                                 matches[j] = strdup(subkeyname);
426                                 j++;
427
428                                 if (j == 1)
429                                         samelen = strlen(matches[j]);
430                                 else
431                                         while (strncmp(matches[j], matches[j-1], samelen) != 0)
432                                                 samelen--;
433                         }
434                 } else if(W_ERROR_EQUAL(status, WERR_NO_MORE_ITEMS)) {
435                         break;
436                 } else {
437                         printf("Error creating completion list: %s\n",
438                                 win_errstr(status));
439                         talloc_free(mem_ctx);
440                         return NULL;
441                 }
442         }
443
444         if (j == 1) { /* No matches at all */
445                 SAFE_FREE(matches);
446                 talloc_free(mem_ctx);
447                 return NULL;
448         }
449
450         if (j == 2) { /* Exact match */
451                 asprintf(&matches[0], "%s%s", base_n, matches[1]);
452         } else {
453                 asprintf(&matches[0], "%s%s", base_n,
454                                 talloc_strndup(mem_ctx, matches[1], samelen));
455         }
456         talloc_free(mem_ctx);
457
458         matches[j] = NULL;
459         return matches;
460 }
461
462 static char **reg_completion(const char *text, int start, int end)
463 {
464         smb_readline_ca_char(' ');
465
466         if (start == 0) {
467                 return reg_complete_command(text, start, end);
468         } else {
469                 return reg_complete_key(text, start, end);
470         }
471 }
472
473 int main(int argc, char **argv)
474 {
475         int opt;
476         const char *file = NULL;
477         poptContext pc;
478         const char *remote = NULL;
479         struct regshell_context *ctx;
480         bool ret = true;
481         struct poptOption long_options[] = {
482                 POPT_AUTOHELP
483                 {"file", 'F', POPT_ARG_STRING, &file, 0, "open hive file", NULL },
484                 {"remote", 'R', POPT_ARG_STRING, &remote, 0, "connect to specified remote server", NULL},
485                 POPT_COMMON_SAMBA
486                 POPT_COMMON_CREDENTIALS
487                 POPT_COMMON_VERSION
488                 { NULL }
489         };
490
491         pc = poptGetContext(argv[0], argc, (const char **) argv, long_options,0);
492
493         while((opt = poptGetNextOpt(pc)) != -1) {
494         }
495
496         ctx = talloc_zero(NULL, struct regshell_context);
497
498         if (remote != NULL) {
499                 ctx->registry = reg_common_open_remote(remote,
500                                                        cmdline_credentials);
501         } else if (file != NULL) {
502                 ctx->current = reg_common_open_file(file, cmdline_credentials);
503                 if (ctx->current == NULL)
504                         return 1;
505                 ctx->registry = ctx->current->context;
506                 ctx->path = talloc_strdup(ctx, "");
507         } else {
508                 ctx->registry = reg_common_open_local(cmdline_credentials);
509         }
510
511         if (ctx->registry == NULL)
512                 return 1;
513
514         if (ctx->current == NULL) {
515                 int i;
516
517                 for (i = 0; reg_predefined_keys[i].handle; i++) {
518                         WERROR err;
519                         err = reg_get_predefined_key(ctx->registry,
520                                                      reg_predefined_keys[i].handle,
521                                                      &ctx->current);
522                         if (W_ERROR_IS_OK(err)) {
523                                 ctx->path = talloc_strdup(ctx,
524                                                           reg_predefined_keys[i].name);
525                                 break;
526                         } else {
527                                 ctx->current = NULL;
528                         }
529                 }
530         }
531
532         if (ctx->current == NULL) {
533                 fprintf(stderr, "Unable to access any of the predefined keys\n");
534                 return -1;
535         }
536
537         poptFreeContext(pc);
538
539         while (true) {
540                 char *line, *prompt;
541
542                 asprintf(&prompt, "%s> ", ctx->path);
543
544                 current_key = ctx->current;             /* No way to pass a void * pointer
545                                                            via readline :-( */
546                 line = smb_readline(prompt, NULL, reg_completion);
547
548                 if (line == NULL)
549                         break;
550
551                 if (line[0] != '\n') {
552                         ret = W_ERROR_IS_OK(process_cmd(ctx, line));
553                 }
554         }
555         talloc_free(ctx);
556
557         return (ret?0:1);
558 }