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/>.
21 * @brief Format dot.reg files
23 * @author Gregor Beck <gb@sernet.de>
27 #include "reg_format.h"
28 #include "reg_parse.h"
29 #include "reg_parse_internal.h"
33 #include "registry/reg_objects.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 /******************************************************************************/
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
55 static int cbuf_print_value_assign(cbuf
* ost
, const char* name
) {
58 ret
= cbuf_putc(ost
, '@');
60 ret
= cbuf_print_quoted_string(ost
, name
);
67 n
= cbuf_putc(ost
, '=');
84 enum fmt_hive hive_fmt
;
85 enum fmt_case hive_case
;
86 enum fmt_case key_case
;
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
);
97 DEBUG(0, ("Unknown hive %*s", len
, hive
));
99 switch(fmt
->hive_fmt
) {
101 hive
= hinfo
->short_name
;
102 len
= hinfo
->short_name_len
;
105 hive
= hinfo
->long_name
;
106 len
= hinfo
->long_name_len
;
109 DEBUG(0, ("Unsupported hive format %d",
110 (int)fmt
->hive_fmt
));
116 return cbuf_puts_case(ost
, hive
, len
, fmt
->hive_case
);
120 cbuf_print_keyname(cbuf
* ost
, const char* key
[], int n
, const struct fmt_key
* fmt
)
123 size_t pos
= cbuf_getpos(ost
);
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') {
135 r
= cbuf_print_hive(ost
, start
, end
-start
, fmt
);
143 r
= cbuf_puts(ost
, fmt
->sep
, -1);
149 r
= cbuf_puts_case(ost
, start
, end
-start
, fmt
->key_case
);
156 while(*end
== '\\') {
164 cbuf_setpos(ost
, pos
);
170 * @defgroup reg_format Format dot.reg file.
176 struct reg_parse_callback reg_parse_callback
;
177 struct reg_format_callback call
;
179 smb_iconv_t fromUTF16
;
183 int reg_format_value_delete(struct reg_format
* f
, const char* name
)
186 cbuf
* line
= cbuf_new(f
);
188 ret
= cbuf_print_value_assign(line
, name
);
193 ret
= cbuf_putc(line
, '-');
198 ret
= f
->call
.writeline(f
->call
.data
, cbuf_gets(line
, 0));
204 /* Todo: write hex if str contains CR or LF */
206 reg_format_value_sz(struct reg_format
* f
, const char* name
, const char* str
)
209 cbuf
* line
= cbuf_new(f
);
211 ret
= cbuf_print_value_assign(line
, name
);
216 ret
= cbuf_print_quoted_string(line
, str
);
221 ret
= f
->call
.writeline(f
->call
.data
, cbuf_gets(line
, 0));
228 static int reg_format_value_dw(struct reg_format
* f
, const char* name
, uint32_t dw
)
231 cbuf
* line
= cbuf_new(f
);
233 ret
= cbuf_print_value_assign(line
, name
);
238 ret
= cbuf_printf(line
, "dword:%08x", dw
);
243 ret
= f
->call
.writeline(f
->call
.data
, cbuf_gets(line
, 0));
249 static int reg_format_value_hex(struct reg_format
* f
, const char* name
, uint32_t type
,
250 const void* data
, size_t len
)
255 const unsigned char* ptr
;
257 cbuf
* line
= cbuf_new(f
);
259 n
= cbuf_print_value_assign(line
, name
);
267 if (type
==REG_BINARY
&& !(f
->flags
& REG_FMT_HEX_BIN
)) {
268 n
=cbuf_puts(line
, "hex:", -1);
270 n
=cbuf_printf(line
, "hex(%x):", type
);
279 for (ptr
=(const unsigned char *)data
; len
>1; len
--,ptr
++) {
280 n
= cbuf_printf(line
, "%02x,", (unsigned)(*ptr
));
287 n
= cbuf_putc(line
, '\\');
292 n
= f
->call
.writeline(f
->call
.data
, cbuf_gets(line
,0));
300 cpl
= cbuf_puts(line
, " ", -1);
309 n
= cbuf_printf(line
, "%02x", (unsigned)(*ptr
));
317 n
= f
->call
.writeline(f
->call
.data
, cbuf_gets(line
,0));
328 int reg_format_value(struct reg_format
* f
, const char* name
, uint32_t type
,
329 const uint8_t* data
, size_t len
)
332 void* mem_ctx
= talloc_new(f
);
336 if (!(f
->flags
& REG_FMT_HEX_SZ
)) {
339 if (pull_ucs2_talloc(mem_ctx
, &str
, (const smb_ucs2_t
*)data
, &dlen
)) {
340 ret
= reg_format_value_sz(f
, name
, str
);
343 DEBUG(0, ("reg_format_value %s: "
344 "pull_ucs2_talloc failed"
345 ", try to write hex\n", name
));
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
);
360 if (f
->fromUTF16
&& (f
->fromUTF16
!= ((smb_iconv_t
)-1))) {
362 size_t dlen
= iconvert_talloc(mem_ctx
, f
->fromUTF16
,
363 (const char*)data
, len
, &str
);
365 ret
= reg_format_value_hex(f
, name
, type
, str
, dlen
);
368 DEBUG(0, ("reg_format_value %s: "
369 "iconvert_talloc failed"
370 ", try to write hex\n", name
));
378 ret
= reg_format_value_hex(f
, name
, type
, data
, len
);
380 talloc_free(mem_ctx
);
385 int reg_format_comment(struct reg_format
* f
, const char* txt
)
388 cbuf
* line
= cbuf_new(f
);
390 ret
= cbuf_putc(line
,';');
395 ret
= cbuf_puts(line
, txt
, -1);
400 ret
= f
->call
.writeline(f
->call
.data
, cbuf_gets(line
, 0));
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
,
416 static const struct reg_parse_callback reg_parse_callback_default
= {
417 .key
= (reg_parse_callback_key_t
)®_format_key
,
418 .val
= (reg_parse_callback_val_t
)®_format_value
,
419 .val_del
= (reg_parse_callback_val_del_t
)®_format_value_delete
,
420 .comment
= (reg_parse_callback_comment_t
)®_format_comment
,
423 struct reg_format
* f
= talloc_zero(talloc_ctx
, struct reg_format
);
428 f
->reg_parse_callback
= reg_parse_callback_default
;
429 f
->reg_parse_callback
.data
= f
;
435 if (str_enc
&& !set_iconv(&f
->fromUTF16
, str_enc
, "UTF-16LE")) {
436 DEBUG(0, ("reg_format_new: failed to set encoding: %s\n",
441 assert(&f
->reg_parse_callback
== (struct reg_parse_callback
*)f
);
448 int reg_format_set_options(struct reg_format
* fmt
, const char* options
)
450 static const char* DEFAULT
="enc=unix,flags=0,sep=\\";
454 void* ctx
= talloc_new(fmt
);
456 if (options
== NULL
) {
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
));
466 } else if ((strcmp(key
, "flags") == 0) && (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>"));
476 } else if ((strcmp(key
, "sep") == 0) && (val
!= NULL
)) {
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; */
489 /* DEBUG(0, ("Invalid hive format: %s\n", val)); */
498 int reg_format_key(struct reg_format
* f
, const char* key
[], size_t n
, bool del
)
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,
509 ret
= cbuf_putc(line
, '[');
515 ret
= cbuf_putc(line
, '-');
521 ret
= cbuf_print_keyname(line
, key
, n
, &key_fmt
);
526 ret
= cbuf_putc(line
, ']');
531 ret
= f
->call
.writeline(f
->call
.data
, "");
536 r
= f
->call
.writeline(f
->call
.data
, cbuf_gets(line
, 0));
549 int reg_format_registry_key(struct reg_format
* f
, struct registry_key
* key
,
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
),
576 struct reg_format_file
579 const char* encoding
;
580 smb_iconv_t fromUnix
;
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
;
591 FILE* file
= fmt_ctx
->file
;
593 if (fmt_ctx
->encoding
) {
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:");
608 static int reg_format_file_writeline(void* ptr
, const char* line
)
612 struct reg_format_file
* fmt_ctx
= (struct reg_format_file
*)ptr
;
615 size
= iconvert_talloc(ptr
, fmt_ctx
->fromUnix
, line
, strlen(line
), &dst
);
617 DEBUG(0, ("reg_format_file_writeline: iconvert_talloc failed >%s<\n", line
));
621 ret
= fwrite(dst
, 1, size
, fmt_ctx
->file
);
626 r
= fwrite(fmt_ctx
->nl
, 1, fmt_ctx
->nl_len
, fmt_ctx
->file
);
627 ret
= (r
< 0) ? r
: ret
+ r
;
634 struct reg_format_file_opt
{
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
= {
652 .flags
= (FMT_HIVE_LONG
<< 12),
656 static const struct reg_format_file_opt REG5
= {
657 .head
= "Windows Registry Editor Version 5.00",
660 .str_enc
= "UTF-16LE",
662 .flags
= (FMT_HIVE_LONG
<< 12),
666 struct reg_format_file_opt ret
= {
671 .str_enc
= "UTF-16LE",
676 void* tmp_ctx
= talloc_new(mem_ctx
);
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
)) {
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
)) {
703 ret
.sep
= talloc_steal(mem_ctx
, val
);
704 } else if (strcmp(key
, "head") == 0) {
706 ret
.head
= talloc_steal(mem_ctx
, val
);
707 } else if (strcmp(key
, "nl") == 0) {
709 ret
.nl
= talloc_steal(mem_ctx
, val
);
710 } else if (strcmp(key
, "bom") == 0) {
716 } else if (strcmp(key
, "regedit4") == 0) {
718 } else if (strcmp(key
, "regedit5") == 0) {
723 talloc_free(tmp_ctx
);
728 struct reg_format
* reg_format_file(const void* talloc_ctx
,
729 const char* filename
,
732 struct reg_format_file
* fmt_ctx
;
733 struct reg_format
* fmt
;
735 struct reg_format_file_opt opt
;
737 struct reg_format_callback reg_format_cb
= {
738 .writeline
= ®_format_file_writeline
741 fmt_ctx
= talloc_zero(talloc_ctx
, struct reg_format_file
);
742 if (fmt_ctx
== 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
);
755 talloc_free(fmt_ctx
);
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",
767 if (!set_iconv(&fmt_ctx
->fromUnix
, opt
.enc
, "unix")) {
768 DEBUG(0, ("reg_format_file: failed to set file encoding %s",
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
)));
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"));
793 ret
= write_bom(fmt_ctx
->file
, opt
.enc
, -1);
799 ret
= fmt
->call
.writeline(fmt
->call
.data
, opt
.head
);