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
) {
60 n
= cbuf_putc(ost
, '@');
62 n
= cbuf_print_quoted_string(ost
, name
);
69 n
= cbuf_putc(ost
, '=');
86 enum fmt_hive hive_fmt
;
87 enum fmt_case hive_case
;
88 enum fmt_case key_case
;
94 cbuf_print_hive(cbuf
* ost
, const char* hive
, int len
, const struct fmt_key
* fmt
)
96 if (fmt
->hive_fmt
!= FMT_HIVE_PRESERVE
) {
97 const struct hive_info
* hinfo
= hive_info(hive
);
99 DEBUG(0, ("Unknown hive %*s", len
, hive
));
101 switch(fmt
->hive_fmt
) {
103 hive
= hinfo
->short_name
;
104 len
= hinfo
->short_name_len
;
107 hive
= hinfo
->long_name
;
108 len
= hinfo
->long_name_len
;
111 DEBUG(0, ("Unsupported hive format %d",
112 (int)fmt
->hive_fmt
));
118 return cbuf_puts_case(ost
, hive
, len
, fmt
->hive_case
);
122 cbuf_print_keyname(cbuf
* ost
, const char* key
[], int n
, const struct fmt_key
* fmt
)
126 size_t pos
= cbuf_getpos(ost
);
129 for (; n
>0; key
++, n
--) {
130 const char* start
= *key
;
131 while(*start
!= '\0') {
132 const char* end
= start
;
133 while(*end
!= '\\' && *end
!= '\0') {
138 r
= cbuf_print_hive(ost
, start
, end
-start
, fmt
);
146 r
= cbuf_puts(ost
, fmt
->sep
, -1);
152 r
= cbuf_puts_case(ost
, start
, end
-start
, fmt
->key_case
);
159 while(*end
== '\\') {
167 cbuf_setpos(ost
, pos
);
173 * @defgroup reg_format Format dot.reg file.
179 struct reg_parse_callback reg_parse_callback
;
180 struct reg_format_callback call
;
182 smb_iconv_t fromUTF16
;
186 int reg_format_value_delete(struct reg_format
* f
, const char* name
)
189 cbuf
* line
= cbuf_new(f
);
191 ret
= cbuf_print_value_assign(line
, name
);
196 ret
= cbuf_putc(line
, '-');
201 ret
= f
->call
.writeline(f
->call
.data
, cbuf_gets(line
, 0));
207 /* Todo: write hex if str contains CR or LF */
209 reg_format_value_sz(struct reg_format
* f
, const char* name
, const char* str
)
212 cbuf
* line
= cbuf_new(f
);
214 ret
= cbuf_print_value_assign(line
, name
);
219 ret
= cbuf_print_quoted_string(line
, str
);
224 ret
= f
->call
.writeline(f
->call
.data
, cbuf_gets(line
, 0));
231 static int reg_format_value_dw(struct reg_format
* f
, const char* name
, uint32_t dw
)
234 cbuf
* line
= cbuf_new(f
);
236 ret
= cbuf_print_value_assign(line
, name
);
241 ret
= cbuf_printf(line
, "dword:%08x", dw
);
246 ret
= f
->call
.writeline(f
->call
.data
, cbuf_gets(line
, 0));
252 static int reg_format_value_hex(struct reg_format
* f
, const char* name
, uint32_t type
,
253 const void* data
, size_t len
)
258 const unsigned char* ptr
;
260 cbuf
* line
= cbuf_new(f
);
262 n
= cbuf_print_value_assign(line
, name
);
270 if (type
==REG_BINARY
&& !(f
->flags
& REG_FMT_HEX_BIN
)) {
271 n
=cbuf_puts(line
, "hex:", -1);
273 n
=cbuf_printf(line
, "hex(%x):", type
);
282 for (ptr
=(const unsigned char *)data
; len
>1; len
--,ptr
++) {
283 n
= cbuf_printf(line
, "%02x,", (unsigned)(*ptr
));
290 n
= cbuf_putc(line
, '\\');
295 n
= f
->call
.writeline(f
->call
.data
, cbuf_gets(line
,0));
303 cpl
= cbuf_puts(line
, " ", -1);
312 n
= cbuf_printf(line
, "%02x", (unsigned)(*ptr
));
320 n
= f
->call
.writeline(f
->call
.data
, cbuf_gets(line
,0));
331 static bool is_zero_terminated_ucs2(const uint8_t* data
, size_t len
) {
332 const size_t idx
= len
/sizeof(smb_ucs2_t
);
333 const smb_ucs2_t
*str
= (const smb_ucs2_t
*)data
;
335 if ((len
% sizeof(smb_ucs2_t
)) != 0) {
343 return (str
[idx
-1] == 0);
346 int reg_format_value(struct reg_format
* f
, const char* name
, uint32_t type
,
347 const uint8_t* data
, size_t len
)
350 void* mem_ctx
= talloc_new(f
);
354 if (!(f
->flags
& REG_FMT_HEX_SZ
)
355 && is_zero_terminated_ucs2(data
, len
))
359 if (pull_ucs2_talloc(mem_ctx
, &str
, (const smb_ucs2_t
*)data
, &dlen
)) {
360 ret
= reg_format_value_sz(f
, name
, str
);
363 DEBUG(0, ("reg_format_value %s: "
364 "pull_ucs2_talloc failed"
365 ", try to write hex\n", name
));
371 if (!(f
->flags
& REG_FMT_HEX_SZ
) && (len
== sizeof(uint32_t))) {
372 uint32_t dw
= IVAL(data
,0);
373 ret
= reg_format_value_dw(f
, name
, dw
);
380 if (f
->fromUTF16
&& (f
->fromUTF16
!= ((smb_iconv_t
)-1))) {
382 size_t dlen
= iconvert_talloc(mem_ctx
, f
->fromUTF16
,
383 (const char*)data
, len
, &str
);
385 ret
= reg_format_value_hex(f
, name
, type
, str
, dlen
);
388 DEBUG(0, ("reg_format_value %s: "
389 "iconvert_talloc failed"
390 ", try to write hex\n", name
));
398 ret
= reg_format_value_hex(f
, name
, type
, data
, len
);
400 talloc_free(mem_ctx
);
405 int reg_format_comment(struct reg_format
* f
, const char* txt
)
408 cbuf
* line
= cbuf_new(f
);
410 ret
= cbuf_putc(line
,';');
415 ret
= cbuf_puts(line
, txt
, -1);
420 ret
= f
->call
.writeline(f
->call
.data
, cbuf_gets(line
, 0));
427 /******************************************************************************/
431 struct reg_format
* reg_format_new(const void* talloc_ctx
,
432 struct reg_format_callback cb
,
433 const char* str_enc
, unsigned flags
,
436 static const struct reg_parse_callback reg_parse_callback_default
= {
437 .key
= (reg_parse_callback_key_t
)®_format_key
,
438 .val
= (reg_parse_callback_val_t
)®_format_value
,
439 .val_del
= (reg_parse_callback_val_del_t
)®_format_value_delete
,
440 .comment
= (reg_parse_callback_comment_t
)®_format_comment
,
443 struct reg_format
* f
= talloc_zero(talloc_ctx
, struct reg_format
);
448 f
->reg_parse_callback
= reg_parse_callback_default
;
449 f
->reg_parse_callback
.data
= f
;
455 if (str_enc
&& !set_iconv(&f
->fromUTF16
, str_enc
, "UTF-16LE")) {
456 DEBUG(0, ("reg_format_new: failed to set encoding: %s\n",
461 assert(&f
->reg_parse_callback
== (struct reg_parse_callback
*)f
);
468 int reg_format_set_options(struct reg_format
* fmt
, const char* options
)
470 static const char* DEFAULT
="enc=unix,flags=0,sep=\\";
474 void* ctx
= talloc_new(fmt
);
476 if (options
== NULL
) {
480 while (srprs_option(&options
, ctx
, &key
, &val
)) {
481 if ((strcmp(key
, "enc") == 0) || (strcmp(key
, "strenc") == 0)) {
482 if (!set_iconv(&fmt
->fromUTF16
, val
, "UTF-16LE")) {
483 DEBUG(0, ("Failed to set encoding: %s\n", val
));
486 } else if ((strcmp(key
, "flags") == 0) && (val
!= NULL
)) {
489 fmt
->flags
= strtol(val
, &end
, 0);
491 if ((end
==NULL
) || (*end
!= '\0')) {
492 DEBUG(0, ("Invalid flags format: %s\n",
493 val
? val
: "<NULL>"));
496 } else if ((strcmp(key
, "sep") == 0) && (val
!= NULL
)) {
498 fmt
->sep
= talloc_steal(fmt
, val
);
501 /* else if (strcmp(key, "hive") == 0) { */
502 /* if (strcmp(val, "short") == 0) { */
503 /* f->hive_fmt = REG_FMT_SHORT_HIVES; */
504 /* } else if (strcmp(val, "long") == 0) { */
505 /* f->hive_fmt = REG_FMT_LONG_HIVES; */
506 /* } else if (strcmp(val, "preserve") == 0) { */
507 /* f->hive_fmt = REG_FMT_PRESERVE_HIVES; */
509 /* DEBUG(0, ("Invalid hive format: %s\n", val)); */
518 int reg_format_key(struct reg_format
* f
, const char* key
[], size_t n
, bool del
)
521 cbuf
* line
= cbuf_new(f
);
522 struct fmt_key key_fmt
= {
523 .key_case
= (f
->flags
>> 4) & 0x0F,
524 .hive_case
= (f
->flags
>> 8) & 0x0F,
525 .hive_fmt
= (f
->flags
>> 12) & 0x0F,
529 ret
= cbuf_putc(line
, '[');
535 ret
= cbuf_putc(line
, '-');
541 ret
= cbuf_print_keyname(line
, key
, n
, &key_fmt
);
546 ret
= cbuf_putc(line
, ']');
551 ret
= f
->call
.writeline(f
->call
.data
, "");
556 r
= f
->call
.writeline(f
->call
.data
, cbuf_gets(line
, 0));
569 int reg_format_registry_key(struct reg_format
* f
, struct registry_key
* key
,
572 const char *knames
[1];
573 knames
[0] = key
->key
->name
;
574 return reg_format_key(f
, knames
, 1, del
);
577 int reg_format_registry_value(struct reg_format
* f
, const char* name
,
578 struct registry_value
* val
)
580 return reg_format_value(f
, name
, val
->type
,
581 val
->data
.data
, val
->data
.length
);
584 int reg_format_regval_blob(struct reg_format
* f
, const char* name
,
585 struct regval_blob
* val
)
588 return reg_format_value(f
,
589 name
? name
: regval_name(val
),
598 struct reg_format_file
601 const char* encoding
;
602 smb_iconv_t fromUnix
;
608 static int reg_format_file_close(struct reg_format
* fmt
)
610 struct reg_format_file
* fmt_ctx
611 = (struct reg_format_file
*) fmt
->call
.data
;
613 FILE* file
= fmt_ctx
->file
;
615 if (fmt_ctx
->encoding
) {
617 snprintf(buf
, sizeof(buf
), "coding: %s", fmt_ctx
->encoding
);
618 reg_format_comment(fmt
, "Local Variables:");
619 reg_format_comment(fmt
, buf
);
620 reg_format_comment(fmt
, "End:");
630 static int reg_format_file_writeline(void* ptr
, const char* line
)
634 struct reg_format_file
* fmt_ctx
= (struct reg_format_file
*)ptr
;
637 size
= iconvert_talloc(ptr
, fmt_ctx
->fromUnix
, line
, strlen(line
), &dst
);
639 DEBUG(0, ("reg_format_file_writeline: iconvert_talloc failed >%s<\n", line
));
643 ret
= fwrite(dst
, 1, size
, fmt_ctx
->file
);
648 r
= fwrite(fmt_ctx
->nl
, 1, fmt_ctx
->nl_len
, fmt_ctx
->file
);
649 ret
= (r
< 0) ? r
: ret
+ r
;
656 struct reg_format_file_opt
{
666 static struct reg_format_file_opt
reg_format_file_opt(void* mem_ctx
, const char* opt
)
668 static const struct reg_format_file_opt REG4
= {
674 .flags
= (FMT_HIVE_LONG
<< 12),
678 static const struct reg_format_file_opt REG5
= {
679 .head
= "Windows Registry Editor Version 5.00",
682 .str_enc
= "UTF-16LE",
684 .flags
= (FMT_HIVE_LONG
<< 12),
688 struct reg_format_file_opt ret
= {
693 .str_enc
= "UTF-16LE",
698 void* tmp_ctx
= talloc_new(mem_ctx
);
706 while(srprs_option(&opt
, tmp_ctx
, &key
, &val
)) {
707 if (strcmp(key
, "enc") == 0) {
708 ret
.enc
= talloc_steal(mem_ctx
, val
);
709 ret
.str_enc
= ret
.enc
;
710 } else if (strcmp(key
, "strenc") == 0) {
711 ret
.str_enc
= talloc_steal(mem_ctx
, val
);
712 } else if (strcmp(key
, "fileenc") == 0) {
713 ret
.enc
= talloc_steal(mem_ctx
, val
);
714 } else if ((strcmp(key
, "flags") == 0) && (val
!= NULL
)) {
717 ret
.flags
= strtol(val
, &end
, 0);
719 if ((end
==NULL
) || (*end
!= '\0')) {
720 DEBUG(0, ("Invalid flags format: %s\n",
721 val
? val
: "<NULL>"));
723 } else if ((strcmp(key
, "sep") == 0) && (val
!= NULL
)) {
725 ret
.sep
= talloc_steal(mem_ctx
, val
);
726 } else if (strcmp(key
, "head") == 0) {
728 ret
.head
= talloc_steal(mem_ctx
, val
);
729 } else if (strcmp(key
, "nl") == 0) {
731 ret
.nl
= talloc_steal(mem_ctx
, val
);
732 } else if (strcmp(key
, "bom") == 0) {
738 } else if (strcmp(key
, "regedit4") == 0) {
740 } else if (strcmp(key
, "regedit5") == 0) {
745 talloc_free(tmp_ctx
);
750 struct reg_format
* reg_format_file(const void* talloc_ctx
,
751 const char* filename
,
754 struct reg_format_file
* fmt_ctx
;
755 struct reg_format
* fmt
;
757 struct reg_format_file_opt opt
;
759 struct reg_format_callback reg_format_cb
= {
760 .writeline
= ®_format_file_writeline
763 fmt_ctx
= talloc_zero(talloc_ctx
, struct reg_format_file
);
764 if (fmt_ctx
== NULL
) {
769 opt
= reg_format_file_opt(fmt_ctx
, options
);
771 reg_format_cb
.data
= fmt_ctx
;
773 fmt
= reg_format_new(talloc_ctx
, reg_format_cb
,
774 opt
.str_enc
, opt
.flags
, opt
.sep
);
777 talloc_free(fmt_ctx
);
781 talloc_steal(fmt
, fmt_ctx
);
783 if (!set_iconv(&fmt
->fromUTF16
, opt
.str_enc
, "UTF-16LE")) { /* HACK */
784 DEBUG(0, ("reg_format_file: failed to set string encoding %s",
789 if (!set_iconv(&fmt_ctx
->fromUnix
, opt
.enc
, "unix")) {
790 DEBUG(0, ("reg_format_file: failed to set file encoding %s",
794 fmt_ctx
->encoding
= talloc_strdup(fmt_ctx
, smbreg_get_charset(opt
.enc
));
796 fmt_ctx
->file
= fopen(filename
, "w");
797 if (fmt_ctx
->file
== NULL
) {
798 DEBUG(0, ("reg_format_file: fopen failed: %s\n", strerror(errno
)));
802 if (setvbuf(fmt_ctx
->file
, NULL
, _IOFBF
, 64000) < 0) {
803 DEBUG(0, ("reg_format_file: setvbuf failed: %s\n", strerror(errno
)));
806 talloc_set_destructor(fmt
, reg_format_file_close
);
808 fmt_ctx
->nl_len
= iconvert_talloc(fmt
, fmt_ctx
->fromUnix
, opt
.nl
, strlen(opt
.nl
), &fmt_ctx
->nl
);
809 if (fmt_ctx
->nl_len
== -1) {
810 DEBUG(0, ("iconvert_talloc failed\n"));
815 ret
= write_bom(fmt_ctx
->file
, opt
.enc
, -1);
821 ret
= fmt
->call
.writeline(fmt
->call
.data
, opt
.head
);