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