2 Unix SMB/CIFS implementation.
3 simple registry frontend
5 Copyright (C) 2002, Richard Sharpe, rsharpe@richardsharpe.com
6 Copyright (C) 2004, Jelmer Vernooij, jelmer@samba.org
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 2 of the License, or
11 (at your option) any later version.
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.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "dynconfig.h"
26 #include "lib/cmdline/popt_common.h"
29 * Routines to parse a REGEDIT4 file
31 * The file consists of:
38 * [cmd:]name=type:value
40 * cmd = a|d|c|add|delete|change|as|ds|cs
42 * There can be more than one key-path and value-spec.
44 * Since we want to support more than one type of file format, we
45 * construct a command-file structure that keeps info about the command file
49 #define FMT_REGEDIT4 0
50 #define FMT_EDITREG1_1 1
52 #define FMT_STRING_REGEDIT4 "REGEDIT4"
53 #define FMT_STRING_EDITREG1_0 "EDITREG1.0"
62 typedef struct val_spec_list {
63 struct val_spec_list *next;
66 char *val; /* Kept as a char string, really? */
69 typedef struct command_s {
73 VAL_SPEC_LIST *val_spec_list, *val_spec_last;
76 typedef struct cmd_line {
81 static void free_val_spec_list(VAL_SPEC_LIST *vl)
84 if (vl->name) free(vl->name);
85 if (vl->val) free(vl->val);
91 * Some routines to handle lines of info in the command files
93 static void skip_to_eol(int fd)
98 while ((rc = read(fd, &ch, 1)) == 1) {
99 if (ch == 0x0A) return;
102 DEBUG(0, ("Could not read file descriptor: %d, %s\n",
103 fd, strerror(errno)));
108 static void free_cmd(CMD *cmd)
112 while (cmd->val_spec_list) {
115 tmp = cmd->val_spec_list;
116 cmd->val_spec_list = tmp->next;
124 static void free_cmd_line(CMD_LINE *cmd_line)
127 if (cmd_line->line) free(cmd_line->line);
132 static void print_line(struct cmd_line *cl)
138 pl = smb_xmalloc(cl->line_len + 1);
140 strncpy(pl, cl->line, cl->line_len);
141 pl[cl->line_len] = 0;
143 fprintf(stdout, "%s\n", pl);
147 #define INIT_ALLOC 10
150 * Read a line from the input file.
151 * NULL returned when EOF and no chars read
152 * Otherwise we return a cmd_line *
153 * Exit if other errors
155 static struct cmd_line *get_cmd_line(int fd)
157 struct cmd_line *cl = (CMD_LINE *)smb_xmalloc(sizeof(CMD_LINE));
161 cl->len = INIT_ALLOC;
164 * Allocate some space for the line. We extend later if needed.
167 cl->line = (char *)smb_xmalloc(INIT_ALLOC);
170 * Now read in the chars to EOL. Don't store the EOL in the
171 * line. What about CR?
174 while ((rc = read(fd, &ch, 1)) == 1 && ch != '\n') {
175 if (ch == '\r') continue; /* skip CR */
176 if (i == cl->len-1) {
178 * Allocate some more memory
180 if ((cl->line = realloc(cl->line, cl->len + INIT_ALLOC)) == NULL) {
181 DEBUG(0, ("Unable to realloc space for line: %s\n",
185 cl->len += INIT_ALLOC;
191 /* read 0 and we were at loc'n 0, return NULL */
192 if (rc == 0 && i == 0) {
205 * parse_value: parse out a value. We pull it apart as:
207 * <value> ::= <value-name>=<type>:<value-string>
209 * <value-name> ::= char-string-without-spaces | '"' char-string '"'
211 * If it parsed OK, return the <value-name> as a string, and the
212 * value type and value-string in parameters.
214 * The value name can be empty. There can only be one empty name in
215 * a list of values. A value of - removes the value entirely.
218 static char *parse_name(char *nstr)
220 int len = 0, start = 0;
221 if (!nstr) return NULL;
225 while (len && nstr[len - 1] == ' ') len--;
227 nstr[len] = 0; /* Trim any spaces ... if there were none, doesn't matter */
230 * Beginning and end should be '"' or neither should be so
232 if ((nstr[0] == '"' && nstr[len - 1] != '"') ||
233 (nstr[0] != '"' && nstr[len - 1] == '"'))
236 if (nstr[0] == '"') {
241 return strndup(&nstr[start], len);
244 static int parse_value_type(char *tstr)
246 int len = strlen(tstr);
248 while (len && tstr[len - 1] == ' ') len--;
251 if (strcmp(tstr, "REG_DWORD") == 0)
253 else if (strcmp(tstr, "dword") == 0)
255 else if (strcmp(tstr, "REG_EXPAND_SZ") == 0)
256 return REG_EXPAND_SZ;
257 else if (strcmp(tstr, "REG_BIN") == 0)
259 else if (strcmp(tstr, "REG_SZ") == 0)
261 else if (strcmp(tstr, "REG_MULTI_SZ") == 0)
263 else if (strcmp(tstr, "-") == 0)
269 static char *parse_val_str(char *vstr)
272 return strndup(vstr, strlen(vstr));
276 static char *parse_value(struct cmd_line *cl, int *vtype, char **val)
278 char *p1 = NULL, *p2 = NULL, *nstr = NULL, *tstr = NULL, *vstr = NULL;
280 if (!cl || !vtype || !val) return NULL;
281 if (!cl->line[0]) return NULL;
283 p1 = strdup(cl->line);
284 /* FIXME: Better return codes etc ... */
285 if (!p1) return NULL;
286 p2 = strchr(p1, '=');
287 if (!p2) return NULL;
289 *p2 = 0; p2++; /* Split into two strings at p2 */
291 /* Now, parse the name ... */
293 nstr = parse_name(p1);
294 if (!nstr) goto error;
296 /* Now, split the remainder and parse on type and val ... */
299 while (*tstr == ' ') tstr++; /* Skip leading white space */
300 p2 = strchr(p2, ':');
303 *p2 = 0; p2++; /* split on the : */
306 *vtype = parse_value_type(tstr);
308 if (!vtype) goto error;
310 if (!p2 || !*p2) return nstr;
312 /* Now, parse the value string. It should return a newly malloc'd string */
314 while (*p2 == ' ') p2++; /* Skip leading space */
315 vstr = parse_val_str(p2);
317 if (!vstr) goto error;
325 if (nstr) free(nstr);
326 if (vstr) free(vstr);
331 * Parse out a key. Look for a correctly formatted key [...]
332 * and whether it is a delete or add? A delete is signalled
333 * by a - in front of the key.
334 * Assumes that there are no leading and trailing spaces
337 static char *parse_key(struct cmd_line *cl, int *cmd)
342 if (cl->line[0] != '[' ||
343 cl->line[cl->line_len - 1] != ']') return NULL;
344 if (cl->line_len == 2) return NULL;
346 if (cl->line[1] == '-') {
347 if (cl->line_len == 3) return NULL;
351 tmp = smb_xmalloc(cl->line_len - 1 - start + 1);
352 strncpy(tmp, &cl->line[start], cl->line_len - 1 - start);
353 tmp[cl->line_len - 1 - start] = 0;
358 * Parse a line to determine if we have a key or a value
359 * We only check for key or val ...
362 static int parse_line(struct cmd_line *cl)
365 if (!cl || cl->len == 0) return 0;
367 if (cl->line[0] == '[') /* No further checking for now */
374 * We seek to offset 0, read in the required number of bytes,
375 * and compare to the correct value.
376 * We then seek back to the original location
378 static int regedit4_file_type(int fd)
383 cur_ofs = lseek(fd, 0, SEEK_CUR); /* Get current offset */
385 DEBUG(0, ("Unable to get current offset: (%d) %s\n", cur_ofs, strerror(errno)));
390 lseek(fd, 0, SEEK_SET);
393 if (read(fd, desc, 8) < 8) {
394 DEBUG(0, ("Unable to read command file format\n"));
400 if (strcmp(desc, FMT_STRING_REGEDIT4) == 0) {
402 lseek(fd, cur_ofs, SEEK_SET);
413 * Run though the data in the line and strip anything after a comment
416 static void strip_comment(struct cmd_line *cl)
422 for (i = 0; i < cl->line_len; i++) {
423 if (cl->line[i] == ';') {
432 * Get a command ... This consists of possibly multiple lines:
435 * possibly Empty line
437 * value ::= <value-name>=<value-type>':'<value-string>
438 * <value-name> is some path, possibly enclosed in quotes ...
439 * We alctually look for the next key to terminate a previous key
440 * if <value-type> == '-', then it is a delete type.
442 static CMD *regedit4_get_cmd(int fd)
444 struct command_s *cmd = NULL;
445 struct cmd_line *cl = NULL;
446 struct val_spec_list *vl = NULL;
448 cmd = (struct command_s *)smb_xmalloc(sizeof(struct command_s));
453 cmd->val_spec_list = cmd->val_spec_last = NULL;
454 while ((cl = get_cmd_line(fd))) {
457 * If it is an empty command line, and we already have a key
458 * then exit from here ... FIXME: Clean up the parser
461 if (cl->line_len == 0 && cmd->key) {
466 strip_comment(cl); /* remove anything beyond a comment char */
467 trim_string(cl->line, " \t", " \t");
469 if (!cl->line[0]) { /* An empty line */
472 else { /* Else, non-empty ... */
474 * Parse out the bits ...
476 switch (parse_line(cl)) {
478 if ((cmd->key = parse_key(cl, &cmd->cmd)) == NULL) {
479 DEBUG(0, ("Error parsing key from line: "));
487 * We need to add the value stuff to the list
488 * There could be a \ on the end which we need to
489 * handle at some time
491 vl = (struct val_spec_list *)smb_xmalloc(sizeof(struct val_spec_list));
494 vl->name = parse_value(cl, &vl->type, &vl->val);
495 if (!vl->name) goto error;
496 if (cmd->val_spec_list == NULL) {
497 cmd->val_spec_list = cmd->val_spec_last = vl;
500 cmd->val_spec_last->next = vl;
501 cmd->val_spec_last = vl;
507 DEBUG(0, ("Unrecognized line in command file: \n"));
514 if (!cmd->cmd) goto error; /* End of file ... */
520 if (cmd) free_cmd(cmd);
524 static int regedit4_exec_cmd(CMD *cmd)
530 static int editreg_1_0_file_type(int fd)
535 cur_ofs = lseek(fd, 0, SEEK_CUR); /* Get current offset */
537 DEBUG(0, ("Unable to get current offset: %s\n", strerror(errno)));
542 lseek(fd, 0, SEEK_SET);
545 if (read(fd, desc, 10) < 10) {
546 DEBUG(0, ("Unable to read command file format\n"));
552 if (strcmp(desc, FMT_STRING_EDITREG1_0) == 0) {
553 lseek(fd, cur_ofs, SEEK_SET);
560 static CMD *editreg_1_0_get_cmd(int fd)
565 static int editreg_1_0_exec_cmd(CMD *cmd)
571 typedef struct command_ops_s {
573 int (*file_type)(int fd);
574 CMD *(*get_cmd)(int fd);
575 int (*exec_cmd)(CMD *cmd);
578 CMD_OPS default_cmd_ops[] = {
579 {0, regedit4_file_type, regedit4_get_cmd, regedit4_exec_cmd},
580 {1, editreg_1_0_file_type, editreg_1_0_get_cmd, editreg_1_0_exec_cmd},
581 {-1, NULL, NULL, NULL}
584 typedef struct command_file_s {
591 * Create a new command file structure
594 static CMD_FILE *cmd_file_create(const char *file)
601 * Let's check if the file exists ...
602 * No use creating the cmd_file structure if the file does not exist
605 if (stat(file, &sbuf) < 0) { /* Not able to access file */
606 DEBUG(0,("Stat on %s failed\n", file));
610 tmp = (CMD_FILE *)smb_xmalloc(sizeof(CMD_FILE));
613 * Let's fill in some of the fields;
616 tmp->name = strdup(file);
618 if ((tmp->fd = open(file, O_RDONLY, 666)) < 0) {
619 DEBUG(0,("Error opening %s\n", file));
625 * Now, try to find the format by indexing through the table
627 while (default_cmd_ops[i].type != -1) {
628 if ((tmp->type = default_cmd_ops[i].file_type(tmp->fd)) >= 0) {
629 tmp->cmd_ops = default_cmd_ops[i];
636 * If we got here, return NULL, as we could not figure out the type
643 DEBUG(0,("Unknown type\n"));
648 * Extract commands from the command file, and execute them.
649 * We pass a table of command callbacks for that
655 * Main code from here on ...
659 * key print function here ...
663 * Sec Desc print functions
666 char *str_type(uint8_t type);
668 static int nt_apply_reg_command_file(struct registry_context *r, const char *cmd_file_name)
671 BOOL modified = False;
672 CMD_FILE *cmd_file = NULL;
673 TALLOC_CTX *mem_ctx = talloc_init("apply_cmd_file");
674 struct registry_key *tmp = NULL;
676 cmd_file = cmd_file_create(cmd_file_name);
678 while ((cmd = cmd_file->cmd_ops.get_cmd(cmd_file->fd)) != NULL) {
681 * Now, apply the requests to the tree ...
685 error = reg_open_key_abs(mem_ctx, r, cmd->key, &tmp);
687 /* If we found it, apply the other bits, else create such a key */
688 if (W_ERROR_EQUAL(error, WERR_DEST_NOT_FOUND)) {
689 if(W_ERROR_IS_OK(reg_key_add_name_recursive_abs(r, cmd->key))) {
690 error = reg_open_key_abs(mem_ctx, r, cmd->key, &tmp);
691 if(!W_ERROR_IS_OK(error)) {
692 DEBUG(0, ("Error finding new key '%s' after it has been added\n", cmd->key));
696 DEBUG(0, ("Error adding new key '%s'\n", cmd->key));
702 while (cmd->val_count) {
703 VAL_SPEC_LIST *val = cmd->val_spec_list;
704 struct registry_value *reg_val = NULL;
706 if (val->type == REG_DELETE) {
707 error = reg_key_get_value_by_name( mem_ctx, tmp, val->name, ®_val);
708 if(W_ERROR_IS_OK(error)) {
709 error = reg_del_value(reg_val);
711 if(!W_ERROR_IS_OK(error)) {
712 DEBUG(0, ("Error removing value '%s'\n", val->name));
717 if(!W_ERROR_IS_OK(reg_val_set(tmp, val->name, val->type, val->val, strlen(val->val)))) {
718 DEBUG(0, ("Error adding new value '%s'\n", val->name));
724 cmd->val_spec_list = val->next;
725 free_val_spec_list(val);
733 * Any value does not matter ...
734 * Find the key if it exists, and delete it ...
737 error = reg_open_key_abs(mem_ctx, r, cmd->key, &tmp);
738 if(!W_ERROR_IS_OK(error)) {
739 DEBUG(0, ("Unable to open key '%s'\n", cmd->key));
743 error = reg_key_del_recursive(tmp);
744 if(!W_ERROR_IS_OK(error)) {
745 DEBUG(0, ("Unable to delete key '%s'\n", cmd->key));
757 int main(int argc, char **argv)
761 const char *location;
762 const char *credentials = NULL;
764 const char *backend = "rpc";
765 struct registry_context *h;
767 struct poptOption long_options[] = {
769 {"backend", 'b', POPT_ARG_STRING, &backend, 'b', "backend to use", NULL},
770 {"credentials", 'c', POPT_ARG_STRING, &credentials, 'c', "credentials (user%password", NULL},
775 if (!lp_load(dyn_CONFIGFILE,True,False,False)) {
776 fprintf(stderr, "Can't load %s - run testparm to debug it\n", dyn_CONFIGFILE);
780 pc = poptGetContext(argv[0], argc, (const char **) argv, long_options,0);
782 while((opt = poptGetNextOpt(pc)) != -1) {
785 setup_logging(argv[0], True);
787 location = poptGetArg(pc);
789 poptPrintUsage(pc, stderr, 0);
793 error = reg_open(&h, backend, location, credentials);
795 fprintf(stderr, "Unable to open '%s' with backend '%s'\n", location, backend);
799 patch = poptGetArg(pc);
800 if(!patch) patch = "/dev/stdin";
803 nt_apply_reg_command_file(h, patch);
805 talloc_destroy(h->mem_ctx);