s3-spoolssd: propagate SIGHUP to children
[Samba.git] / source3 / registry / reg_format.c
blobf2b0846b11225d2cae83a2c6083306b7bf4c0ac4
1 /*
2 * Samba Unix/Linux SMB client library
4 * Copyright (C) Gregor Beck 2010
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 /**
21 * @brief Format dot.reg files
22 * @file reg_format.c
23 * @author Gregor Beck <gb@sernet.de>
24 * @date Sep 2010
27 #include "reg_format.h"
28 #include "reg_parse.h"
29 #include "reg_parse_internal.h"
30 #include "cbuf.h"
31 #include "srprs.h"
32 #include "registry.h"
33 #include "registry/reg_objects.h"
34 #include <assert.h>
36 static void cstr_unescape(char* val)
38 all_string_sub(val, "\\r", "\r", 0);
39 all_string_sub(val, "\\n", "\n", 0);
40 all_string_sub(val, "\\t", "\t", 0);
41 all_string_sub(val, "\\\\", "\\", 0);
44 /******************************************************************************/
46 /**
47 * Print value assign to stream.
49 * @param[out] ost outstream
50 * @param[in] name string
52 * @return numner of bytes written, -1 on error
53 * @see srprs_val_name
55 static int cbuf_print_value_assign(cbuf* ost, const char* name) {
56 int ret, n;
57 if (*name == '\0') {
58 ret = cbuf_putc(ost, '@');
59 } else {
60 ret = cbuf_print_quoted_string(ost, name);
63 if (ret<0) {
64 return ret;
67 n = cbuf_putc(ost, '=');
68 if (n < 0) {
69 return n;
71 ret += n;
73 return ret;
76 enum fmt_hive {
77 FMT_HIVE_PRESERVE=0,
78 FMT_HIVE_SHORT,
79 FMT_HIVE_LONG
83 struct fmt_key {
84 enum fmt_hive hive_fmt;
85 enum fmt_case hive_case;
86 enum fmt_case key_case;
87 const char* sep;
91 static int
92 cbuf_print_hive(cbuf* ost, const char* hive, int len, const struct fmt_key* fmt)
94 if (fmt->hive_fmt != FMT_HIVE_PRESERVE) {
95 const struct hive_info* hinfo = hive_info(hive, len);
96 if (hinfo == NULL) {
97 DEBUG(0, ("Unknown hive %*s", len, hive));
98 } else {
99 switch(fmt->hive_fmt) {
100 case FMT_HIVE_SHORT:
101 hive = hinfo->short_name;
102 len = hinfo->short_name_len;
103 break;
104 case FMT_HIVE_LONG:
105 hive = hinfo->long_name;
106 len = hinfo->long_name_len;
107 break;
108 default:
109 DEBUG(0, ("Unsupported hive format %d",
110 (int)fmt->hive_fmt));
111 return -1;
116 return cbuf_puts_case(ost, hive, len, fmt->hive_case);
119 static int
120 cbuf_print_keyname(cbuf* ost, const char* key[], int n, const struct fmt_key* fmt)
122 int r, ret=0;
123 size_t pos = cbuf_getpos(ost);
124 bool hive = true;
126 for (; n>0; key++, n--) {
127 const char* start = *key;
128 while(*start != '\0') {
129 const char* end = start;
130 while(*end != '\\' && *end != '\0') {
131 end++;
134 if (hive) {
135 r = cbuf_print_hive(ost, start, end-start, fmt);
136 if (r < 0) {
137 goto fail;
140 ret += r;
141 hive = false;
142 } else {
143 r = cbuf_puts(ost, fmt->sep, -1);
144 if (r < 0) {
145 goto fail;
147 ret += r;
149 r = cbuf_puts_case(ost, start, end-start, fmt->key_case);
150 if (r < 0) {
151 goto fail;
153 ret += r;
156 while(*end == '\\') {
157 end++;
159 start = end;
162 return ret;
163 fail:
164 cbuf_setpos(ost, pos);
165 return r;
167 /**@}*/
170 * @defgroup reg_format Format dot.reg file.
171 * @{
174 struct reg_format
176 struct reg_parse_callback reg_parse_callback;
177 struct reg_format_callback call;
178 unsigned flags;
179 smb_iconv_t fromUTF16;
180 const char* sep;
183 int reg_format_value_delete(struct reg_format* f, const char* name)
185 int ret;
186 cbuf* line = cbuf_new(f);
188 ret = cbuf_print_value_assign(line, name);
189 if (ret < 0) {
190 goto done;
193 ret = cbuf_putc(line, '-');
194 if (ret < 0 ) {
195 goto done;
198 ret = f->call.writeline(f->call.data, cbuf_gets(line, 0));
199 done:
200 talloc_free(line);
201 return ret;
204 /* Todo: write hex if str contains CR or LF */
205 static int
206 reg_format_value_sz(struct reg_format* f, const char* name, const char* str)
208 int ret;
209 cbuf* line = cbuf_new(f);
211 ret = cbuf_print_value_assign(line, name);
212 if (ret < 0) {
213 goto done;
216 ret = cbuf_print_quoted_string(line, str);
217 if (ret < 0) {
218 goto done;
221 ret = f->call.writeline(f->call.data, cbuf_gets(line, 0));
223 done:
224 talloc_free(line);
225 return ret;
228 static int reg_format_value_dw(struct reg_format* f, const char* name, uint32_t dw)
230 int ret;
231 cbuf* line = cbuf_new(f);
233 ret = cbuf_print_value_assign(line, name);
234 if (ret < 0) {
235 goto done;
238 ret = cbuf_printf(line, "dword:%08x", dw);
239 if (ret < 0) {
240 goto done;
243 ret = f->call.writeline(f->call.data, cbuf_gets(line, 0));
244 done:
245 talloc_free(line);
246 return ret;
249 static int reg_format_value_hex(struct reg_format* f, const char* name, uint32_t type,
250 const void* data, size_t len)
252 int n;
253 int cpl=0;
254 int ret=0;
255 const unsigned char* ptr;
257 cbuf* line = cbuf_new(f);
259 n = cbuf_print_value_assign(line, name);
260 if (n < 0) {
261 ret = n;
262 goto done;
265 cpl += n;
267 if (type==REG_BINARY && !(f->flags & REG_FMT_HEX_BIN)) {
268 n=cbuf_puts(line, "hex:", -1);
269 } else {
270 n=cbuf_printf(line, "hex(%x):", type);
272 if (n < 0) {
273 ret = n;
274 goto done;
277 cpl += n;
279 for (ptr=(const unsigned char *)data; len>1; len--,ptr++) {
280 n = cbuf_printf(line, "%02x,", (unsigned)(*ptr));
281 if (n < 0) {
282 return n;
284 cpl += n;
286 if ( cpl > 76 ) {
287 n = cbuf_putc(line, '\\');
288 if (n< 0) {
289 return n;
292 n = f->call.writeline(f->call.data, cbuf_gets(line,0));
293 if (n < 0) {
294 ret = n;
295 goto done;
297 ret += n;
299 cbuf_clear(line);
300 cpl = cbuf_puts(line, " ", -1);
301 if (cpl < 0) {
302 ret = cpl;
303 goto done;
308 if ( len > 0 ) {
309 n = cbuf_printf(line, "%02x", (unsigned)(*ptr));
310 if (n < 0) {
311 ret = n;
312 goto done;
314 cpl += n;
317 n = f->call.writeline(f->call.data, cbuf_gets(line,0));
318 if (n < 0) {
319 ret = n;
320 goto done;
322 ret += n;
323 done:
324 talloc_free(line);
325 return ret;
328 int reg_format_value(struct reg_format* f, const char* name, uint32_t type,
329 const uint8_t* data, size_t len)
331 int ret = 0;
332 void* mem_ctx = talloc_new(f);
334 switch (type) {
335 case REG_SZ:
336 if (!(f->flags & REG_FMT_HEX_SZ)) {
337 char* str = NULL;
338 size_t dlen;
339 if (pull_ucs2_talloc(mem_ctx, &str, (const smb_ucs2_t*)data, &dlen)) {
340 ret = reg_format_value_sz(f, name, str);
341 goto done;
342 } else {
343 DEBUG(0, ("reg_format_value %s: "
344 "pull_ucs2_talloc failed"
345 ", try to write hex\n", name));
348 break;
350 case REG_DWORD:
351 if (!(f->flags & REG_FMT_HEX_SZ) && (len == sizeof(uint32_t))) {
352 uint32_t dw = IVAL(data,0);
353 ret = reg_format_value_dw(f, name, dw);
354 goto done;
356 break;
358 case REG_MULTI_SZ:
359 case REG_EXPAND_SZ:
360 if (f->fromUTF16 && (f->fromUTF16 != ((smb_iconv_t)-1))) {
361 char* str = NULL;
362 size_t dlen = iconvert_talloc(mem_ctx, f->fromUTF16,
363 (const char*)data, len, &str);
364 if (dlen != -1) {
365 ret = reg_format_value_hex(f, name, type, str, dlen);
366 goto done;
367 } else {
368 DEBUG(0, ("reg_format_value %s: "
369 "iconvert_talloc failed"
370 ", try to write hex\n", name));
373 break;
374 default:
375 break;
378 ret = reg_format_value_hex(f, name, type, data, len);
379 done:
380 talloc_free(mem_ctx);
381 return ret;
385 int reg_format_comment(struct reg_format* f, const char* txt)
387 int ret;
388 cbuf* line = cbuf_new(f);
390 ret = cbuf_putc(line,';');
391 if (ret<0) {
392 goto done;
395 ret = cbuf_puts(line, txt, -1);
396 if (ret < 0) {
397 goto done;
400 ret = f->call.writeline(f->call.data, cbuf_gets(line, 0));
401 done:
402 talloc_free(line);
403 return ret;
407 /******************************************************************************/
411 struct reg_format* reg_format_new(const void* talloc_ctx,
412 struct reg_format_callback cb,
413 const char* str_enc, unsigned flags,
414 const char* sep)
416 static const struct reg_parse_callback reg_parse_callback_default = {
417 .key = (reg_parse_callback_key_t)&reg_format_key,
418 .val = (reg_parse_callback_val_t)&reg_format_value,
419 .val_del = (reg_parse_callback_val_del_t)&reg_format_value_delete,
420 .comment = (reg_parse_callback_comment_t)&reg_format_comment,
423 struct reg_format* f = talloc_zero(talloc_ctx, struct reg_format);
424 if (f == NULL) {
425 return NULL;
428 f->reg_parse_callback = reg_parse_callback_default;
429 f->reg_parse_callback.data = f;
431 f->call = cb;
432 f->flags = flags;
433 f->sep = sep;
435 if (str_enc && !set_iconv(&f->fromUTF16, str_enc, "UTF-16LE")) {
436 DEBUG(0, ("reg_format_new: failed to set encoding: %s\n",
437 str_enc));
438 goto fail;
441 assert(&f->reg_parse_callback == (struct reg_parse_callback*)f);
442 return f;
443 fail:
444 talloc_free(f);
445 return NULL;
448 int reg_format_set_options(struct reg_format* fmt, const char* options)
450 static const char* DEFAULT ="enc=unix,flags=0,sep=\\";
452 int ret = 0;
453 char *key, *val;
454 void* ctx = talloc_new(fmt);
456 if (options == NULL) {
457 options = DEFAULT;
460 while (srprs_option(&options, ctx, &key, &val)) {
461 if ((strcmp(key, "enc") == 0) || (strcmp(key, "strenc") == 0)) {
462 if (!set_iconv(&fmt->fromUTF16, val, "UTF-16LE")) {
463 DEBUG(0, ("Failed to set encoding: %s\n", val));
464 ret = -1;
466 } else if ((strcmp(key, "flags") == 0) && (val != NULL)) {
467 char* end = NULL;
468 if (val != NULL) {
469 fmt->flags = strtol(val, &end, 0);
471 if ((end==NULL) || (*end != '\0')) {
472 DEBUG(0, ("Invalid flags format: %s\n",
473 val ? val : "<NULL>"));
474 ret = -1;
476 } else if ((strcmp(key, "sep") == 0) && (val != NULL)) {
477 cstr_unescape(val);
478 fmt->sep = talloc_steal(fmt, val);
481 /* else if (strcmp(key, "hive") == 0) { */
482 /* if (strcmp(val, "short") == 0) { */
483 /* f->hive_fmt = REG_FMT_SHORT_HIVES; */
484 /* } else if (strcmp(val, "long") == 0) { */
485 /* f->hive_fmt = REG_FMT_LONG_HIVES; */
486 /* } else if (strcmp(val, "preserve") == 0) { */
487 /* f->hive_fmt = REG_FMT_PRESERVE_HIVES; */
488 /* } else { */
489 /* DEBUG(0, ("Invalid hive format: %s\n", val)); */
490 /* ret = -1; */
491 /* } */
492 /* } */
494 talloc_free(ctx);
495 return ret;
498 int reg_format_key(struct reg_format* f, const char* key[], size_t n, bool del)
500 int ret, r;
501 cbuf* line = cbuf_new(f);
502 struct fmt_key key_fmt = {
503 .key_case = (f->flags >> 4) & 0x0F,
504 .hive_case = (f->flags >> 8) & 0x0F,
505 .hive_fmt = (f->flags >> 12) & 0x0F,
506 .sep = f->sep,
509 ret = cbuf_putc(line, '[');
510 if (ret < 0) {
511 goto done;
514 if (del) {
515 ret = cbuf_putc(line, '-');
516 if (ret < 0) {
517 goto done;
521 ret = cbuf_print_keyname(line, key, n, &key_fmt);
522 if (ret < 0) {
523 goto done;
526 ret = cbuf_putc(line, ']');
527 if (ret < 0) {
528 goto done;
531 ret = f->call.writeline(f->call.data, "");
532 if (ret < 0) {
533 goto done;
536 r = f->call.writeline(f->call.data, cbuf_gets(line, 0));
537 if (r < 0) {
538 ret = r;
539 goto done;
541 ret += r;
543 done:
544 talloc_free(line);
545 return ret;
549 int reg_format_registry_key(struct reg_format* f, struct registry_key* key,
550 bool del)
552 return reg_format_key(f, (const char**)&key->key->name, 1, del);
555 int reg_format_registry_value(struct reg_format* f, const char* name,
556 struct registry_value* val)
558 return reg_format_value(f, name, val->type,
559 val->data.data, val->data.length);
562 int reg_format_regval_blob(struct reg_format* f, const char* name,
563 struct regval_blob* val)
566 return reg_format_value(f,
567 name ? name : regval_name(val),
568 regval_type(val),
569 regval_data_p(val),
570 regval_size(val));
573 /**@}*/
576 struct reg_format_file
578 FILE* file;
579 const char* encoding;
580 smb_iconv_t fromUnix;
581 char* nl;
582 size_t nl_len;
586 static int reg_format_file_close(struct reg_format* fmt)
588 struct reg_format_file* fmt_ctx
589 = (struct reg_format_file*) fmt->call.data;
590 int ret = 0;
591 FILE* file = fmt_ctx->file;
593 if (fmt_ctx->encoding) {
594 char buf[32];
595 snprintf(buf, sizeof(buf), "coding: %s", fmt_ctx->encoding);
596 reg_format_comment(fmt, "Local Variables:");
597 reg_format_comment(fmt, buf);
598 reg_format_comment(fmt, "End:");
601 if (file != NULL) {
602 ret = fclose(file);
605 return ret;
608 static int reg_format_file_writeline(void* ptr, const char* line)
610 size_t size;
611 char* dst=NULL;
612 struct reg_format_file* fmt_ctx = (struct reg_format_file*)ptr;
613 int ret, r;
615 size = iconvert_talloc(ptr, fmt_ctx->fromUnix, line, strlen(line), &dst);
616 if (size == -1 ) {
617 DEBUG(0, ("reg_format_file_writeline: iconvert_talloc failed >%s<\n", line));
618 return -1;
621 ret = fwrite(dst, 1, size, fmt_ctx->file);
622 if (ret < 0) {
623 goto done;
626 r = fwrite(fmt_ctx->nl, 1, fmt_ctx->nl_len, fmt_ctx->file);
627 ret = (r < 0) ? r : ret + r;
629 done:
630 talloc_free(dst);
631 return ret;
634 struct reg_format_file_opt {
635 const char* head;
636 const char* nl;
637 const char* enc;
638 bool bom;
639 const char* str_enc;
640 unsigned flags;
641 const char* sep;
644 static struct reg_format_file_opt reg_format_file_opt(void* mem_ctx, const char* opt)
646 static const struct reg_format_file_opt REG4 = {
647 .head = "REGEDIT4",
648 .nl = "\r\n",
649 .enc = "dos",
650 .str_enc = "dos",
651 .bom = false,
652 .flags = (FMT_HIVE_LONG << 12),
653 .sep = "\\",
656 static const struct reg_format_file_opt REG5 = {
657 .head = "Windows Registry Editor Version 5.00",
658 .nl = "\r\n",
659 .enc = "UTF-16LE",
660 .str_enc = "UTF-16LE",
661 .bom = true,
662 .flags = (FMT_HIVE_LONG << 12),
663 .sep = "\\",
666 struct reg_format_file_opt ret = {
667 .head = REG5.head,
668 .nl = "\n",
669 .enc = "unix",
670 .bom = false,
671 .str_enc = "UTF-16LE",
672 .flags = 0,
673 .sep = "\\",
676 void* tmp_ctx = talloc_new(mem_ctx);
678 char *key, *val;
680 if (opt == NULL) {
681 goto done;
684 while(srprs_option(&opt, tmp_ctx, &key, &val)) {
685 if (strcmp(key, "enc") == 0) {
686 ret.enc = talloc_steal(mem_ctx, val);
687 ret.str_enc = ret.enc;
688 } else if (strcmp(key, "strenc") == 0) {
689 ret.str_enc = talloc_steal(mem_ctx, val);
690 } else if (strcmp(key, "fileenc") == 0) {
691 ret.enc = talloc_steal(mem_ctx, val);
692 } else if ((strcmp(key, "flags") == 0) && (val != NULL)) {
693 char* end = NULL;
694 if (val != NULL) {
695 ret.flags = strtol(val, &end, 0);
697 if ((end==NULL) || (*end != '\0')) {
698 DEBUG(0, ("Invalid flags format: %s\n",
699 val ? val : "<NULL>"));
701 } else if ((strcmp(key, "sep") == 0) && (val != NULL)) {
702 cstr_unescape(val);
703 ret.sep = talloc_steal(mem_ctx, val);
704 } else if (strcmp(key, "head") == 0) {
705 cstr_unescape(val);
706 ret.head = talloc_steal(mem_ctx, val);
707 } else if (strcmp(key, "nl") == 0) {
708 cstr_unescape(val);
709 ret.nl = talloc_steal(mem_ctx, val);
710 } else if (strcmp(key, "bom") == 0) {
711 if (val == NULL) {
712 ret.bom = true;
713 } else {
714 ret.bom = atoi(val);
716 } else if (strcmp(key, "regedit4") == 0) {
717 ret = REG4;
718 } else if (strcmp(key, "regedit5") == 0) {
719 ret = REG5;
722 done:
723 talloc_free(tmp_ctx);
724 return ret;
728 struct reg_format* reg_format_file(const void* talloc_ctx,
729 const char* filename,
730 const char* options)
732 struct reg_format_file* fmt_ctx;
733 struct reg_format* fmt;
734 int ret;
735 struct reg_format_file_opt opt;
737 struct reg_format_callback reg_format_cb = {
738 .writeline = &reg_format_file_writeline
741 fmt_ctx = talloc_zero(talloc_ctx, struct reg_format_file);
742 if (fmt_ctx == NULL) {
743 errno = ENOMEM;
744 return NULL;
747 opt = reg_format_file_opt(fmt_ctx, options);
749 reg_format_cb.data = fmt_ctx;
751 fmt = reg_format_new(talloc_ctx, reg_format_cb,
752 opt.str_enc, opt.flags, opt.sep);
753 if (fmt == NULL) {
754 errno = ENOMEM;
755 talloc_free(fmt_ctx);
756 return NULL;
759 talloc_steal(fmt, fmt_ctx);
761 if (!set_iconv(&fmt->fromUTF16, opt.str_enc, "UTF-16LE")) { /* HACK */
762 DEBUG(0, ("reg_format_file: failed to set string encoding %s",
763 opt.str_enc));
764 goto fail;
767 if (!set_iconv(&fmt_ctx->fromUnix, opt.enc, "unix")) {
768 DEBUG(0, ("reg_format_file: failed to set file encoding %s",
769 opt.enc));
770 goto fail;
772 fmt_ctx->encoding = talloc_strdup(fmt_ctx, get_charset(opt.enc));
774 fmt_ctx->file = fopen(filename, "w");
775 if (fmt_ctx->file == NULL) {
776 DEBUG(0, ("reg_format_file: fopen failed: %s\n", strerror(errno)));
777 goto fail;
780 if (setvbuf(fmt_ctx->file, NULL, _IOFBF, 64000) < 0) {
781 DEBUG(0, ("reg_format_file: setvbuf failed: %s\n", strerror(errno)));
784 talloc_set_destructor(fmt, reg_format_file_close);
786 fmt_ctx->nl_len = iconvert_talloc(fmt, fmt_ctx->fromUnix, opt.nl, strlen(opt.nl), &fmt_ctx->nl);
787 if (fmt_ctx->nl_len == -1) {
788 DEBUG(0, ("iconvert_talloc failed\n"));
789 goto fail;
792 if (opt.bom) {
793 ret = write_bom(fmt_ctx->file, opt.enc, -1);
794 if (ret < 0) {
795 goto fail;
799 ret = fmt->call.writeline(fmt->call.data, opt.head);
800 if (ret < 0) {
801 goto fail;
804 return fmt;
805 fail:
806 talloc_free(fmt);
807 return NULL;