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>
28 #include "reg_format.h"
29 #include "reg_parse.h"
30 #include "reg_parse_internal.h"
34 #include "registry/reg_objects.h"
37 static void cstr_unescape(char* val
)
39 all_string_sub(val
, "\\r", "\r", 0);
40 all_string_sub(val
, "\\n", "\n", 0);
41 all_string_sub(val
, "\\t", "\t", 0);
42 all_string_sub(val
, "\\\\", "\\", 0);
45 /******************************************************************************/
48 * Print value assign to stream.
50 * @param[out] ost outstream
51 * @param[in] name string
53 * @return numner of bytes written, -1 on error
56 static int cbuf_print_value_assign(cbuf
* ost
, const char* name
) {
59 ret
= cbuf_putc(ost
, '@');
61 ret
= cbuf_print_quoted_string(ost
, name
);
68 n
= cbuf_putc(ost
, '=');
85 enum fmt_hive hive_fmt
;
86 enum fmt_case hive_case
;
87 enum fmt_case key_case
;
93 cbuf_print_hive(cbuf
* ost
, const char* hive
, int len
, const struct fmt_key
* fmt
)
95 if (fmt
->hive_fmt
!= FMT_HIVE_PRESERVE
) {
96 const struct hive_info
* hinfo
= hive_info(hive
, len
);
98 DEBUG(0, ("Unknown hive %*s", len
, hive
));
100 switch(fmt
->hive_fmt
) {
102 hive
= hinfo
->short_name
;
103 len
= hinfo
->short_name_len
;
106 hive
= hinfo
->long_name
;
107 len
= hinfo
->long_name_len
;
110 DEBUG(0, ("Unsupported hive format %d",
111 (int)fmt
->hive_fmt
));
117 return cbuf_puts_case(ost
, hive
, len
, fmt
->hive_case
);
121 cbuf_print_keyname(cbuf
* ost
, const char* key
[], int n
, const struct fmt_key
* fmt
)
124 size_t pos
= cbuf_getpos(ost
);
127 for (; n
>0; key
++, n
--) {
128 const char* start
= *key
;
129 while(*start
!= '\0') {
130 const char* end
= start
;
131 while(*end
!= '\\' && *end
!= '\0') {
136 r
= cbuf_print_hive(ost
, start
, end
-start
, fmt
);
144 r
= cbuf_puts(ost
, fmt
->sep
, -1);
150 r
= cbuf_puts_case(ost
, start
, end
-start
, fmt
->key_case
);
157 while(*end
== '\\') {
165 cbuf_setpos(ost
, pos
);
171 * @defgroup reg_format Format dot.reg file.
177 struct reg_parse_callback reg_parse_callback
;
178 struct reg_format_callback call
;
180 smb_iconv_t fromUTF16
;
184 int reg_format_value_delete(struct reg_format
* f
, const char* name
)
187 cbuf
* line
= cbuf_new(f
);
189 ret
= cbuf_print_value_assign(line
, name
);
194 ret
= cbuf_putc(line
, '-');
199 ret
= f
->call
.writeline(f
->call
.data
, cbuf_gets(line
, 0));
205 /* Todo: write hex if str contains CR or LF */
207 reg_format_value_sz(struct reg_format
* f
, const char* name
, const char* str
)
210 cbuf
* line
= cbuf_new(f
);
212 ret
= cbuf_print_value_assign(line
, name
);
217 ret
= cbuf_print_quoted_string(line
, str
);
222 ret
= f
->call
.writeline(f
->call
.data
, cbuf_gets(line
, 0));
229 static int reg_format_value_dw(struct reg_format
* f
, const char* name
, uint32_t dw
)
232 cbuf
* line
= cbuf_new(f
);
234 ret
= cbuf_print_value_assign(line
, name
);
239 ret
= cbuf_printf(line
, "dword:%08x", dw
);
244 ret
= f
->call
.writeline(f
->call
.data
, cbuf_gets(line
, 0));
250 static int reg_format_value_hex(struct reg_format
* f
, const char* name
, uint32_t type
,
251 const void* data
, size_t len
)
256 const unsigned char* ptr
;
258 cbuf
* line
= cbuf_new(f
);
260 n
= cbuf_print_value_assign(line
, name
);
268 if (type
==REG_BINARY
&& !(f
->flags
& REG_FMT_HEX_BIN
)) {
269 n
=cbuf_puts(line
, "hex:", -1);
271 n
=cbuf_printf(line
, "hex(%x):", type
);
280 for (ptr
=(const unsigned char *)data
; len
>1; len
--,ptr
++) {
281 n
= cbuf_printf(line
, "%02x,", (unsigned)(*ptr
));
288 n
= cbuf_putc(line
, '\\');
293 n
= f
->call
.writeline(f
->call
.data
, cbuf_gets(line
,0));
301 cpl
= cbuf_puts(line
, " ", -1);
310 n
= cbuf_printf(line
, "%02x", (unsigned)(*ptr
));
318 n
= f
->call
.writeline(f
->call
.data
, cbuf_gets(line
,0));
329 static bool is_zero_terminated_ucs2(const uint8_t* data
, size_t len
) {
330 const size_t idx
= len
/sizeof(smb_ucs2_t
);
331 const smb_ucs2_t
*str
= (const smb_ucs2_t
*)data
;
333 if ((len
% sizeof(smb_ucs2_t
)) != 0) {
341 return (str
[idx
-1] == 0);
344 int reg_format_value(struct reg_format
* f
, const char* name
, uint32_t type
,
345 const uint8_t* data
, size_t len
)
348 void* mem_ctx
= talloc_new(f
);
352 if (!(f
->flags
& REG_FMT_HEX_SZ
)
353 && is_zero_terminated_ucs2(data
, len
))
357 if (pull_ucs2_talloc(mem_ctx
, &str
, (const smb_ucs2_t
*)data
, &dlen
)) {
358 ret
= reg_format_value_sz(f
, name
, str
);
361 DEBUG(0, ("reg_format_value %s: "
362 "pull_ucs2_talloc failed"
363 ", try to write hex\n", name
));
369 if (!(f
->flags
& REG_FMT_HEX_SZ
) && (len
== sizeof(uint32_t))) {
370 uint32_t dw
= IVAL(data
,0);
371 ret
= reg_format_value_dw(f
, name
, dw
);
378 if (f
->fromUTF16
&& (f
->fromUTF16
!= ((smb_iconv_t
)-1))) {
380 size_t dlen
= iconvert_talloc(mem_ctx
, f
->fromUTF16
,
381 (const char*)data
, len
, &str
);
383 ret
= reg_format_value_hex(f
, name
, type
, str
, dlen
);
386 DEBUG(0, ("reg_format_value %s: "
387 "iconvert_talloc failed"
388 ", try to write hex\n", name
));
396 ret
= reg_format_value_hex(f
, name
, type
, data
, len
);
398 talloc_free(mem_ctx
);
403 int reg_format_comment(struct reg_format
* f
, const char* txt
)
406 cbuf
* line
= cbuf_new(f
);
408 ret
= cbuf_putc(line
,';');
413 ret
= cbuf_puts(line
, txt
, -1);
418 ret
= f
->call
.writeline(f
->call
.data
, cbuf_gets(line
, 0));
425 /******************************************************************************/
429 struct reg_format
* reg_format_new(const void* talloc_ctx
,
430 struct reg_format_callback cb
,
431 const char* str_enc
, unsigned flags
,
434 static const struct reg_parse_callback reg_parse_callback_default
= {
435 .key
= (reg_parse_callback_key_t
)®_format_key
,
436 .val
= (reg_parse_callback_val_t
)®_format_value
,
437 .val_del
= (reg_parse_callback_val_del_t
)®_format_value_delete
,
438 .comment
= (reg_parse_callback_comment_t
)®_format_comment
,
441 struct reg_format
* f
= talloc_zero(talloc_ctx
, struct reg_format
);
446 f
->reg_parse_callback
= reg_parse_callback_default
;
447 f
->reg_parse_callback
.data
= f
;
453 if (str_enc
&& !set_iconv(&f
->fromUTF16
, str_enc
, "UTF-16LE")) {
454 DEBUG(0, ("reg_format_new: failed to set encoding: %s\n",
459 assert(&f
->reg_parse_callback
== (struct reg_parse_callback
*)f
);
466 int reg_format_set_options(struct reg_format
* fmt
, const char* options
)
468 static const char* DEFAULT
="enc=unix,flags=0,sep=\\";
472 void* ctx
= talloc_new(fmt
);
474 if (options
== NULL
) {
478 while (srprs_option(&options
, ctx
, &key
, &val
)) {
479 if ((strcmp(key
, "enc") == 0) || (strcmp(key
, "strenc") == 0)) {
480 if (!set_iconv(&fmt
->fromUTF16
, val
, "UTF-16LE")) {
481 DEBUG(0, ("Failed to set encoding: %s\n", val
));
484 } else if ((strcmp(key
, "flags") == 0) && (val
!= NULL
)) {
487 fmt
->flags
= strtol(val
, &end
, 0);
489 if ((end
==NULL
) || (*end
!= '\0')) {
490 DEBUG(0, ("Invalid flags format: %s\n",
491 val
? val
: "<NULL>"));
494 } else if ((strcmp(key
, "sep") == 0) && (val
!= NULL
)) {
496 fmt
->sep
= talloc_steal(fmt
, val
);
499 /* else if (strcmp(key, "hive") == 0) { */
500 /* if (strcmp(val, "short") == 0) { */
501 /* f->hive_fmt = REG_FMT_SHORT_HIVES; */
502 /* } else if (strcmp(val, "long") == 0) { */
503 /* f->hive_fmt = REG_FMT_LONG_HIVES; */
504 /* } else if (strcmp(val, "preserve") == 0) { */
505 /* f->hive_fmt = REG_FMT_PRESERVE_HIVES; */
507 /* DEBUG(0, ("Invalid hive format: %s\n", val)); */
516 int reg_format_key(struct reg_format
* f
, const char* key
[], size_t n
, bool del
)
519 cbuf
* line
= cbuf_new(f
);
520 struct fmt_key key_fmt
= {
521 .key_case
= (f
->flags
>> 4) & 0x0F,
522 .hive_case
= (f
->flags
>> 8) & 0x0F,
523 .hive_fmt
= (f
->flags
>> 12) & 0x0F,
527 ret
= cbuf_putc(line
, '[');
533 ret
= cbuf_putc(line
, '-');
539 ret
= cbuf_print_keyname(line
, key
, n
, &key_fmt
);
544 ret
= cbuf_putc(line
, ']');
549 ret
= f
->call
.writeline(f
->call
.data
, "");
554 r
= f
->call
.writeline(f
->call
.data
, cbuf_gets(line
, 0));
567 int reg_format_registry_key(struct reg_format
* f
, struct registry_key
* key
,
570 return reg_format_key(f
, (const char**)&key
->key
->name
, 1, del
);
573 int reg_format_registry_value(struct reg_format
* f
, const char* name
,
574 struct registry_value
* val
)
576 return reg_format_value(f
, name
, val
->type
,
577 val
->data
.data
, val
->data
.length
);
580 int reg_format_regval_blob(struct reg_format
* f
, const char* name
,
581 struct regval_blob
* val
)
584 return reg_format_value(f
,
585 name
? name
: regval_name(val
),
594 struct reg_format_file
597 const char* encoding
;
598 smb_iconv_t fromUnix
;
604 static int reg_format_file_close(struct reg_format
* fmt
)
606 struct reg_format_file
* fmt_ctx
607 = (struct reg_format_file
*) fmt
->call
.data
;
609 FILE* file
= fmt_ctx
->file
;
611 if (fmt_ctx
->encoding
) {
613 snprintf(buf
, sizeof(buf
), "coding: %s", fmt_ctx
->encoding
);
614 reg_format_comment(fmt
, "Local Variables:");
615 reg_format_comment(fmt
, buf
);
616 reg_format_comment(fmt
, "End:");
626 static int reg_format_file_writeline(void* ptr
, const char* line
)
630 struct reg_format_file
* fmt_ctx
= (struct reg_format_file
*)ptr
;
633 size
= iconvert_talloc(ptr
, fmt_ctx
->fromUnix
, line
, strlen(line
), &dst
);
635 DEBUG(0, ("reg_format_file_writeline: iconvert_talloc failed >%s<\n", line
));
639 ret
= fwrite(dst
, 1, size
, fmt_ctx
->file
);
644 r
= fwrite(fmt_ctx
->nl
, 1, fmt_ctx
->nl_len
, fmt_ctx
->file
);
645 ret
= (r
< 0) ? r
: ret
+ r
;
652 struct reg_format_file_opt
{
662 static struct reg_format_file_opt
reg_format_file_opt(void* mem_ctx
, const char* opt
)
664 static const struct reg_format_file_opt REG4
= {
670 .flags
= (FMT_HIVE_LONG
<< 12),
674 static const struct reg_format_file_opt REG5
= {
675 .head
= "Windows Registry Editor Version 5.00",
678 .str_enc
= "UTF-16LE",
680 .flags
= (FMT_HIVE_LONG
<< 12),
684 struct reg_format_file_opt ret
= {
689 .str_enc
= "UTF-16LE",
694 void* tmp_ctx
= talloc_new(mem_ctx
);
702 while(srprs_option(&opt
, tmp_ctx
, &key
, &val
)) {
703 if (strcmp(key
, "enc") == 0) {
704 ret
.enc
= talloc_steal(mem_ctx
, val
);
705 ret
.str_enc
= ret
.enc
;
706 } else if (strcmp(key
, "strenc") == 0) {
707 ret
.str_enc
= talloc_steal(mem_ctx
, val
);
708 } else if (strcmp(key
, "fileenc") == 0) {
709 ret
.enc
= talloc_steal(mem_ctx
, val
);
710 } else if ((strcmp(key
, "flags") == 0) && (val
!= NULL
)) {
713 ret
.flags
= strtol(val
, &end
, 0);
715 if ((end
==NULL
) || (*end
!= '\0')) {
716 DEBUG(0, ("Invalid flags format: %s\n",
717 val
? val
: "<NULL>"));
719 } else if ((strcmp(key
, "sep") == 0) && (val
!= NULL
)) {
721 ret
.sep
= talloc_steal(mem_ctx
, val
);
722 } else if (strcmp(key
, "head") == 0) {
724 ret
.head
= talloc_steal(mem_ctx
, val
);
725 } else if (strcmp(key
, "nl") == 0) {
727 ret
.nl
= talloc_steal(mem_ctx
, val
);
728 } else if (strcmp(key
, "bom") == 0) {
734 } else if (strcmp(key
, "regedit4") == 0) {
736 } else if (strcmp(key
, "regedit5") == 0) {
741 talloc_free(tmp_ctx
);
746 struct reg_format
* reg_format_file(const void* talloc_ctx
,
747 const char* filename
,
750 struct reg_format_file
* fmt_ctx
;
751 struct reg_format
* fmt
;
753 struct reg_format_file_opt opt
;
755 struct reg_format_callback reg_format_cb
= {
756 .writeline
= ®_format_file_writeline
759 fmt_ctx
= talloc_zero(talloc_ctx
, struct reg_format_file
);
760 if (fmt_ctx
== NULL
) {
765 opt
= reg_format_file_opt(fmt_ctx
, options
);
767 reg_format_cb
.data
= fmt_ctx
;
769 fmt
= reg_format_new(talloc_ctx
, reg_format_cb
,
770 opt
.str_enc
, opt
.flags
, opt
.sep
);
773 talloc_free(fmt_ctx
);
777 talloc_steal(fmt
, fmt_ctx
);
779 if (!set_iconv(&fmt
->fromUTF16
, opt
.str_enc
, "UTF-16LE")) { /* HACK */
780 DEBUG(0, ("reg_format_file: failed to set string encoding %s",
785 if (!set_iconv(&fmt_ctx
->fromUnix
, opt
.enc
, "unix")) {
786 DEBUG(0, ("reg_format_file: failed to set file encoding %s",
790 fmt_ctx
->encoding
= talloc_strdup(fmt_ctx
, get_charset(opt
.enc
));
792 fmt_ctx
->file
= fopen(filename
, "w");
793 if (fmt_ctx
->file
== NULL
) {
794 DEBUG(0, ("reg_format_file: fopen failed: %s\n", strerror(errno
)));
798 if (setvbuf(fmt_ctx
->file
, NULL
, _IOFBF
, 64000) < 0) {
799 DEBUG(0, ("reg_format_file: setvbuf failed: %s\n", strerror(errno
)));
802 talloc_set_destructor(fmt
, reg_format_file_close
);
804 fmt_ctx
->nl_len
= iconvert_talloc(fmt
, fmt_ctx
->fromUnix
, opt
.nl
, strlen(opt
.nl
), &fmt_ctx
->nl
);
805 if (fmt_ctx
->nl_len
== -1) {
806 DEBUG(0, ("iconvert_talloc failed\n"));
811 ret
= write_bom(fmt_ctx
->file
, opt
.enc
, -1);
817 ret
= fmt
->call
.writeline(fmt
->call
.data
, opt
.head
);