r3546: including includes.h twice causes gcc 3.4 to crash with pch
[ira/wip.git] / source4 / lib / registry / tools / regpatch.c
1 /* 
2    Unix SMB/CIFS implementation.
3    simple registry frontend
4    
5    Copyright (C) 2002, Richard Sharpe, rsharpe@richardsharpe.com
6    Copyright (C) 2004, Jelmer Vernooij, jelmer@samba.org
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 2 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, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24 #include "dynconfig.h"
25 #include "registry.h"
26 #include "lib/cmdline/popt_common.h"
27
28 /*
29  * Routines to parse a REGEDIT4 file
30  * 
31  * The file consists of:
32  * 
33  * REGEDIT4
34  * \[[-]key-path\]\n
35  * <value-spec>*
36  *
37  * Format:
38  * [cmd:]name=type:value
39  *
40  * cmd = a|d|c|add|delete|change|as|ds|cs
41  *
42  * There can be more than one key-path and value-spec.
43  *
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
46  */
47
48 #define FMT_UNREC -1
49 #define FMT_REGEDIT4 0
50 #define FMT_EDITREG1_1 1
51
52 #define FMT_STRING_REGEDIT4 "REGEDIT4"
53 #define FMT_STRING_EDITREG1_0 "EDITREG1.0"
54
55 #define CMD_NONE     0
56 #define CMD_ADD_KEY  1
57 #define CMD_DEL_KEY  2
58
59 #define CMD_KEY 1
60 #define CMD_VAL 2
61
62 typedef struct val_spec_list {
63   struct val_spec_list *next;
64   char *name;
65   int type;
66   char *val;    /* Kept as a char string, really? */
67 } VAL_SPEC_LIST;
68
69 typedef struct command_s {
70   int cmd;
71   char *key;
72   int val_count;
73   VAL_SPEC_LIST *val_spec_list, *val_spec_last;
74 } CMD;
75
76 typedef struct cmd_line {
77   int len, line_len;
78   char *line;
79 } CMD_LINE;
80
81 static void free_val_spec_list(VAL_SPEC_LIST *vl)
82 {
83   if (!vl) return;
84   if (vl->name) free(vl->name);
85   if (vl->val) free(vl->val);
86   free(vl);
87
88 }
89
90 /* 
91  * Some routines to handle lines of info in the command files
92  */
93 static void skip_to_eol(int fd)
94 {
95   int rc;
96   char ch = 0;
97
98   while ((rc = read(fd, &ch, 1)) == 1) {
99     if (ch == 0x0A) return;
100   }
101   if (rc < 0) {
102     DEBUG(0, ("Could not read file descriptor: %d, %s\n",
103             fd, strerror(errno)));
104     exit(1);
105   }
106 }
107
108 static void free_cmd(CMD *cmd)
109 {
110   if (!cmd) return;
111
112   while (cmd->val_spec_list) {
113     VAL_SPEC_LIST *tmp;
114
115     tmp = cmd->val_spec_list;
116     cmd->val_spec_list = tmp->next;
117     free(tmp);
118   }
119
120   free(cmd);
121
122 }
123
124 static void free_cmd_line(CMD_LINE *cmd_line)
125 {
126   if (cmd_line) {
127     if (cmd_line->line) free(cmd_line->line);
128     free(cmd_line);
129   }
130 }
131
132 static void print_line(struct cmd_line *cl)
133 {
134   char *pl;
135
136   if (!cl) return;
137
138   pl = smb_xmalloc(cl->line_len + 1);
139
140   strncpy(pl, cl->line, cl->line_len);
141   pl[cl->line_len] = 0;
142
143   fprintf(stdout, "%s\n", pl);
144   free(pl);
145 }
146
147 #define INIT_ALLOC 10 
148
149 /*
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
154  */
155 static struct cmd_line *get_cmd_line(int fd)
156 {
157   struct cmd_line *cl = (CMD_LINE *)smb_xmalloc(sizeof(CMD_LINE));
158   int i = 0, rc;
159   uint8_t ch;
160
161   cl->len = INIT_ALLOC;
162
163   /*
164    * Allocate some space for the line. We extend later if needed.
165    */
166
167   cl->line = (char *)smb_xmalloc(INIT_ALLOC);
168
169   /*
170    * Now read in the chars to EOL. Don't store the EOL in the 
171    * line. What about CR?
172    */
173
174   while ((rc = read(fd, &ch, 1)) == 1 && ch != '\n') {
175     if (ch == '\r') continue; /* skip CR */
176     if (i == cl->len-1) {
177       /*
178        * Allocate some more memory
179        */
180       if ((cl->line = realloc(cl->line, cl->len + INIT_ALLOC)) == NULL) {
181         DEBUG(0, ("Unable to realloc space for line: %s\n",
182                 strerror(errno)));
183         exit(1);
184       }
185       cl->len += INIT_ALLOC;
186     }
187     cl->line[i] = ch;
188     i++;
189   }
190
191   /* read 0 and we were at loc'n 0, return NULL */
192   if (rc == 0 && i == 0) {
193     free_cmd_line(cl);
194     return NULL;
195   }
196
197   cl->line[i] = '\0';
198   cl->line_len = i;
199
200   return cl;
201
202 }
203
204 /*
205  * parse_value: parse out a value. We pull it apart as:
206  *
207  * <value> ::= <value-name>=<type>:<value-string>
208  *
209  * <value-name> ::= char-string-without-spaces | '"' char-string '"'
210  *
211  * If it parsed OK, return the <value-name> as a string, and the
212  * value type and value-string in parameters.
213  *
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.  
216  */
217
218 static char *parse_name(char *nstr)
219 {
220   int len = 0, start = 0;
221   if (!nstr) return NULL;
222
223   len = strlen(nstr);
224
225   while (len && nstr[len - 1] == ' ') len--;
226
227   nstr[len] = 0; /* Trim any spaces ... if there were none, doesn't matter */
228
229   /*
230    * Beginning and end should be '"' or neither should be so
231    */
232   if ((nstr[0] == '"' && nstr[len - 1] != '"') ||
233       (nstr[0] != '"' && nstr[len - 1] == '"'))
234     return NULL;
235
236   if (nstr[0] == '"') {
237     start = 1;
238     len -= 2;
239   }
240
241   return strndup(&nstr[start], len);
242 }
243
244 static int parse_value_type(char *tstr)
245 {
246   int len = strlen(tstr);
247   
248   while (len && tstr[len - 1] == ' ') len--;
249   tstr[len] = 0;
250
251   if (strcmp(tstr, "REG_DWORD") == 0)
252     return REG_DWORD;
253   else if (strcmp(tstr, "dword") == 0)
254     return REG_DWORD;
255   else if (strcmp(tstr, "REG_EXPAND_SZ") == 0)
256     return REG_EXPAND_SZ;
257   else if (strcmp(tstr, "REG_BIN") == 0)
258     return REG_BINARY;
259   else if (strcmp(tstr, "REG_SZ") == 0)
260     return REG_SZ;
261   else if (strcmp(tstr, "REG_MULTI_SZ") == 0)
262     return REG_MULTI_SZ;
263   else if (strcmp(tstr, "-") == 0)
264     return REG_DELETE;
265
266   return 0;
267 }
268
269 static char *parse_val_str(char *vstr)
270 {
271   
272   return strndup(vstr, strlen(vstr));
273
274 }
275
276 static char *parse_value(struct cmd_line *cl, int *vtype, char **val)
277 {
278   char *p1 = NULL, *p2 = NULL, *nstr = NULL, *tstr = NULL, *vstr = NULL;
279   
280   if (!cl || !vtype || !val) return NULL;
281   if (!cl->line[0]) return NULL;
282
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;
288
289   *p2 = 0; p2++; /* Split into two strings at p2 */
290
291   /* Now, parse the name ... */
292
293   nstr = parse_name(p1);
294   if (!nstr) goto error;
295
296   /* Now, split the remainder and parse on type and val ... */
297
298   tstr = p2;
299   while (*tstr == ' ') tstr++; /* Skip leading white space */
300   p2 = strchr(p2, ':');
301
302   if (p2) {
303     *p2 = 0; p2++; /* split on the : */
304   }
305
306   *vtype = parse_value_type(tstr);
307
308   if (!vtype) goto error;
309
310   if (!p2 || !*p2) return nstr;
311
312   /* Now, parse the value string. It should return a newly malloc'd string */
313   
314   while (*p2 == ' ') p2++; /* Skip leading space */
315   vstr = parse_val_str(p2);
316
317   if (!vstr) goto error;
318
319   *val = vstr;
320
321   return nstr;
322
323  error:
324   if (p1) free(p1);
325   if (nstr) free(nstr);
326   if (vstr) free(vstr);
327   return NULL;
328 }
329
330 /*
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
335  */
336
337 static char *parse_key(struct cmd_line *cl, int *cmd)
338 {
339   int start = 1;
340   char *tmp;
341
342   if (cl->line[0] != '[' ||
343       cl->line[cl->line_len - 1] != ']') return NULL;
344   if (cl->line_len == 2) return NULL;
345   *cmd = CMD_ADD_KEY;
346   if (cl->line[1] == '-') {
347     if (cl->line_len == 3) return NULL;
348     start = 2;
349     *cmd = CMD_DEL_KEY;
350   }
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;
354   return tmp;
355 }
356
357 /*
358  * Parse a line to determine if we have a key or a value
359  * We only check for key or val ...
360  */
361
362 static int parse_line(struct cmd_line *cl)
363 {
364
365   if (!cl || cl->len == 0) return 0;
366
367   if (cl->line[0] == '[')  /* No further checking for now */
368     return CMD_KEY;
369   else 
370     return CMD_VAL;
371 }
372
373 /*
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
377  */
378 static int regedit4_file_type(int fd)
379 {
380   int cur_ofs = 0;
381   char desc[9];
382
383   cur_ofs = lseek(fd, 0, SEEK_CUR); /* Get current offset */
384   if (cur_ofs < 0) {
385     DEBUG(0, ("Unable to get current offset: (%d) %s\n", cur_ofs, strerror(errno)));
386     exit(1);  /* FIXME */
387   }
388
389   if (cur_ofs) {
390     lseek(fd, 0, SEEK_SET);
391   }
392
393   if (read(fd, desc, 8) < 8) {
394     DEBUG(0, ("Unable to read command file format\n")); 
395     exit(2);  /* FIXME */
396   }
397
398   desc[8] = 0;
399
400   if (strcmp(desc, FMT_STRING_REGEDIT4) == 0) {
401     if (cur_ofs) {
402       lseek(fd, cur_ofs, SEEK_SET);
403     } else {
404       skip_to_eol(fd);
405     }
406     return FMT_REGEDIT4;
407   }
408
409   return FMT_UNREC;
410 }
411
412 /*
413  * Run though the data in the line and strip anything after a comment
414  * char.
415  */
416 static void strip_comment(struct cmd_line *cl)
417 {
418   int i;
419
420   if (!cl) return;
421
422   for (i = 0; i < cl->line_len; i++) {
423     if (cl->line[i] == ';') {
424                 cl->line[i] = '\0';
425       cl->line_len = i;
426       return;
427     }
428   }
429 }
430
431 /* 
432  * Get a command ... This consists of possibly multiple lines:
433  * [key]
434  * values*
435  * possibly Empty line
436  *
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.
441  */
442 static CMD *regedit4_get_cmd(int fd)
443 {
444   struct command_s *cmd = NULL;
445   struct cmd_line *cl = NULL;
446   struct val_spec_list *vl = NULL;
447
448   cmd = (struct command_s *)smb_xmalloc(sizeof(struct command_s));
449
450   cmd->cmd = CMD_NONE;
451   cmd->key = NULL;
452   cmd->val_count = 0;
453   cmd->val_spec_list = cmd->val_spec_last = NULL;
454   while ((cl = get_cmd_line(fd))) {
455
456     /*
457      * If it is an empty command line, and we already have a key
458      * then exit from here ... FIXME: Clean up the parser
459      */
460
461     if (cl->line_len == 0 && cmd->key) {
462       free_cmd_line(cl);
463       break;
464     } 
465
466     strip_comment(cl);     /* remove anything beyond a comment char */
467         trim_string(cl->line, " \t", " \t");
468
469     if (!cl->line[0]) {    /* An empty line */
470       free_cmd_line(cl);
471     }
472     else {                 /* Else, non-empty ... */
473       /* 
474        * Parse out the bits ... 
475        */
476       switch (parse_line(cl)) {
477       case CMD_KEY:
478         if ((cmd->key = parse_key(cl, &cmd->cmd)) == NULL) {
479           DEBUG(0, ("Error parsing key from line: "));
480           print_line(cl);
481           DEBUG(0, ("\n"));
482         }
483         break;
484
485       case CMD_VAL:
486         /*
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
490          */
491         vl = (struct val_spec_list *)smb_xmalloc(sizeof(struct val_spec_list));
492         vl->next = NULL;
493         vl->val = NULL;
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;
498         }
499         else {
500           cmd->val_spec_last->next = vl;
501           cmd->val_spec_last = vl;
502         }
503         cmd->val_count++;
504         break;
505
506       default:
507         DEBUG(0, ("Unrecognized line in command file: \n"));
508         print_line(cl);
509         break;
510       }
511     }
512
513   }
514   if (!cmd->cmd) goto error; /* End of file ... */
515
516   return cmd;
517
518  error:
519   if (vl) free(vl);
520   if (cmd) free_cmd(cmd);
521   return NULL;
522 }
523
524 static int regedit4_exec_cmd(CMD *cmd)
525 {
526
527   return 0;
528 }
529
530 static int editreg_1_0_file_type(int fd)
531 {
532   int cur_ofs = 0;
533   char desc[11];
534
535   cur_ofs = lseek(fd, 0, SEEK_CUR); /* Get current offset */
536   if (cur_ofs < 0) {
537     DEBUG(0, ("Unable to get current offset: %s\n", strerror(errno)));
538     exit(1);  /* FIXME */
539   }
540
541   if (cur_ofs) {
542     lseek(fd, 0, SEEK_SET);
543   }
544
545   if (read(fd, desc, 10) < 10) {
546     DEBUG(0, ("Unable to read command file format\n")); 
547     exit(2);  /* FIXME */
548   }
549
550   desc[10] = 0;
551
552   if (strcmp(desc, FMT_STRING_EDITREG1_0) == 0) {
553     lseek(fd, cur_ofs, SEEK_SET);
554     return FMT_REGEDIT4;
555   }
556
557   return FMT_UNREC;
558 }
559
560 static CMD *editreg_1_0_get_cmd(int fd)
561 {
562   return NULL;
563 }
564
565 static int editreg_1_0_exec_cmd(CMD *cmd)
566 {
567
568   return -1;
569 }
570
571 typedef struct command_ops_s {
572   int type;
573   int (*file_type)(int fd);
574   CMD *(*get_cmd)(int fd);
575   int (*exec_cmd)(CMD *cmd);
576 } CMD_OPS;
577
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}
582 }; 
583
584 typedef struct command_file_s {
585   char *name;
586   int type, fd;
587   CMD_OPS cmd_ops;
588 } CMD_FILE;
589
590 /*
591  * Create a new command file structure
592  */
593
594 static CMD_FILE *cmd_file_create(const char *file)
595 {
596   CMD_FILE *tmp;
597   struct stat sbuf;
598   int i = 0;
599
600   /*
601    * Let's check if the file exists ...
602    * No use creating the cmd_file structure if the file does not exist
603    */
604
605   if (stat(file, &sbuf) < 0) { /* Not able to access file */
606         DEBUG(0,("Stat on %s failed\n", file));
607     return NULL;
608   }
609
610   tmp = (CMD_FILE *)smb_xmalloc(sizeof(CMD_FILE)); 
611
612   /*
613    * Let's fill in some of the fields;
614    */
615
616   tmp->name = strdup(file);
617
618   if ((tmp->fd = open(file, O_RDONLY, 666)) < 0) {
619         DEBUG(0,("Error opening %s\n", file));
620     free(tmp);
621     return NULL;
622   }
623
624   /*
625    * Now, try to find the format by indexing through the table
626    */
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];
630       return tmp;
631     }
632     i++;
633   }
634
635   /* 
636    * If we got here, return NULL, as we could not figure out the type
637    * of command file.
638    *
639    * What about errors? 
640    */
641
642   free(tmp);
643   DEBUG(0,("Unknown type\n"));
644   return NULL;
645 }
646
647 /*
648  * Extract commands from the command file, and execute them.
649  * We pass a table of command callbacks for that 
650  */
651
652 /* FIXME */
653
654 /*
655  * Main code from here on ...
656  */
657
658 /*
659  * key print function here ...
660  */
661
662 /*
663  * Sec Desc print functions 
664  */
665
666 char *str_type(uint8_t type);
667
668 static int nt_apply_reg_command_file(struct registry_context *r, const char *cmd_file_name)
669 {
670         CMD *cmd;
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;
675         WERROR error;
676         cmd_file = cmd_file_create(cmd_file_name);
677
678         while ((cmd = cmd_file->cmd_ops.get_cmd(cmd_file->fd)) != NULL) {
679
680                 /*
681                  * Now, apply the requests to the tree ...
682                  */
683                 switch (cmd->cmd) {
684                 case CMD_ADD_KEY: 
685                   error = reg_open_key_abs(mem_ctx, r, cmd->key, &tmp);
686
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));
693                                         continue;
694                                   }
695                           } else {
696                                         DEBUG(0, ("Error adding new key '%s'\n", cmd->key));
697                                         continue;
698                           }
699                           modified = True;
700                   }
701
702                   while (cmd->val_count) {
703                           VAL_SPEC_LIST *val = cmd->val_spec_list;
704                           struct registry_value *reg_val = NULL;
705
706                           if (val->type == REG_DELETE) {
707                                   error = reg_key_get_value_by_name( mem_ctx, tmp, val->name, &reg_val);
708                                   if(W_ERROR_IS_OK(error)) {
709                                           error = reg_del_value(reg_val);
710                                   }
711                                   if(!W_ERROR_IS_OK(error)) {
712                                         DEBUG(0, ("Error removing value '%s'\n", val->name));
713                                   }
714                                   modified = True;
715                           }
716                           else {
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));
719                                           continue;
720                                   }
721                                   modified = True;
722                           }
723
724                           cmd->val_spec_list = val->next;
725                           free_val_spec_list(val);
726                           cmd->val_count--;
727                   }
728
729                   break;
730
731                 case CMD_DEL_KEY:
732                   /* 
733                    * Any value does not matter ...
734                    * Find the key if it exists, and delete it ...
735                    */
736
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));
740                           continue;
741                   }
742                   
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));
746                           continue;
747                   }
748                   modified = True;
749                   break;
750                 }
751         }
752         free_cmd(cmd);
753
754         return modified;
755 }
756
757  int main(int argc, char **argv)
758 {
759         int opt;
760         poptContext pc;
761         const char *location;
762         const char *credentials = NULL;
763         const char *patch;
764         const char *backend = "rpc";
765         struct registry_context *h;
766         WERROR error;
767         struct poptOption long_options[] = {
768                 POPT_AUTOHELP
769                 {"backend", 'b', POPT_ARG_STRING, &backend, 'b', "backend to use", NULL},
770                 {"credentials", 'c', POPT_ARG_STRING, &credentials, 'c', "credentials (user%password", NULL},
771                 POPT_TABLEEND
772         };
773
774
775         if (!lp_load(dyn_CONFIGFILE,True,False,False)) {
776                 fprintf(stderr, "Can't load %s - run testparm to debug it\n", dyn_CONFIGFILE);
777         }
778
779
780         pc = poptGetContext(argv[0], argc, (const char **) argv, long_options,0);
781
782         while((opt = poptGetNextOpt(pc)) != -1) {
783         }
784
785         setup_logging(argv[0], True);
786
787         location = poptGetArg(pc);
788         if(!location) {
789                 poptPrintUsage(pc, stderr, 0);
790                 return 1;
791         }
792
793         error = reg_open(&h, backend, location, credentials);
794         if(!h) {
795                 fprintf(stderr, "Unable to open '%s' with backend '%s'\n", location, backend);
796                 return 1;
797         }
798
799         patch = poptGetArg(pc);
800         if(!patch) patch = "/dev/stdin";
801         poptFreeContext(pc);
802
803         nt_apply_reg_command_file(h, patch);
804
805         talloc_destroy(h->mem_ctx);
806
807         return 0;
808 }