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 Parser for dot.reg files
23 * @author Gregor Beck <gb@sernet.de>
29 #include "system/filesys.h"
32 #include "reg_parse_internal.h"
33 #include "reg_parse.h"
34 #include "reg_format.h"
44 enum reg_parse_state
{
52 struct reg_format_callback reg_format_callback
;
58 struct reg_parse_callback call
;
61 enum reg_parse_state state
;
62 struct reg_parse_options
* opt
;
63 smb_iconv_t str2UTF16
;
68 * @defgroup action Action
71 static bool act_key(struct reg_parse
* p
, cbuf
* keyname
, bool del
)
73 const char* name
= cbuf_gets(keyname
, 0);
74 cbuf_swap(p
->key
, keyname
);
76 assert(p
->state
== STATE_DEFAULT
|| p
->state
== STATE_KEY_OPEN
);
77 p
->state
= del
? STATE_DEFAULT
: STATE_KEY_OPEN
;
80 p
->ret
= p
->call
.key(p
->call
.data
, &name
, 1, del
);
84 static bool value_callback(struct reg_parse
* p
)
86 const char* name
= cbuf_gets(p
->valname
,0);
87 const uint8_t* val
= (const uint8_t*)cbuf_gets(p
->valblob
,0);
88 size_t len
= cbuf_getpos(p
->valblob
);
91 p
->ret
= p
->call
.val(p
->call
.data
, name
, p
->valtype
, val
, len
);
95 static bool act_val_hex(struct reg_parse
* p
, cbuf
* value
, bool cont
)
97 cbuf_swap(p
->valblob
, value
);
98 assert((p
->state
== STATE_KEY_OPEN
) || (p
->state
== STATE_VAL_HEX_CONT
));
101 p
->state
= STATE_VAL_HEX_CONT
;
103 p
->state
= STATE_KEY_OPEN
;
105 switch (p
->valtype
) {
108 if (p
->str2UTF16
!= NULL
) {
110 const char* src
= cbuf_gets(p
->valblob
, 0);
111 const size_t slen
= cbuf_getpos(p
->valblob
);
112 size_t dlen
= iconvert_talloc(p
,
117 cbuf_swapptr(p
->valblob
, &dst
, dlen
);
119 DEBUG(0, ("iconvert_talloc failed\n"));
128 return value_callback(p
);
133 static bool act_val_dw(struct reg_parse
* p
, uint32_t val
)
135 assert(p
->valtype
== REG_DWORD
);
136 assert(p
->state
== STATE_KEY_OPEN
);
138 cbuf_clear(p
->valblob
);
140 if (cbuf_putdw(p
->valblob
, val
) < 0) {
143 return value_callback(p
);
146 static bool act_val_sz(struct reg_parse
* p
, cbuf
* value
, bool cont
)
148 cbuf_swap(p
->valblob
, value
);
150 assert(p
->valtype
== REG_SZ
);
151 assert((p
->state
== STATE_KEY_OPEN
) || (p
->state
== STATE_VAL_SZ_CONT
));
154 p
->state
= STATE_VAL_SZ_CONT
;
158 const char* src
= cbuf_gets(p
->valblob
, 0);
160 p
->state
= STATE_KEY_OPEN
;
163 if (convert_string_talloc(p
->valblob
, CH_UNIX
, CH_UTF16LE
,
167 cbuf_swapptr(p
->valblob
, &dst
, dlen
);
169 DEBUG(0, ("convert_string_talloc failed: >%s<\n"
170 "use it as is\t", src
));
175 return value_callback(p
);
180 static bool act_val_del(struct reg_parse
* p
)
182 const char* name
= cbuf_gets(p
->valname
, 0);
184 assert(p
->call
.val_del
);
185 p
->ret
= p
->call
.val_del(p
->call
.data
, name
);
189 static bool act_comment (struct reg_parse
* p
, const char* txt
)
191 assert(p
->call
.comment
);
192 p
->ret
= p
->call
.comment(p
->call
.data
, txt
);
198 static int nop_callback_key(void* private_data
,
206 static int nop_callback_val(void* private_data
,
215 static int nop_callback_del(void* data
, const char* str
)
220 struct reg_parse
* reg_parse_new(const void* ctx
,
221 struct reg_parse_callback cb
,
222 const char* str_enc
, unsigned flags
)
224 struct reg_parse
* s
= talloc_zero(ctx
, struct reg_parse
);
227 s
->key
= cbuf_new(s
);
228 s
->valname
= cbuf_new(s
);
229 s
->valblob
= cbuf_new(s
);
230 s
->tmp
= cbuf_new(s
);
231 if ( (s
->tmp
== NULL
) || (s
->valblob
== NULL
)
232 || (s
->valname
== NULL
) || (s
->key
== NULL
) )
237 s
->reg_format_callback
.writeline
= (reg_format_callback_writeline_t
)®_parse_line
;
238 s
->reg_format_callback
.data
= s
;
241 if (cb
.key
== NULL
) {
242 cb
.key
= (reg_parse_callback_key_t
)&nop_callback_key
;
244 if (cb
.val
== NULL
) {
245 cb
.val
= (reg_parse_callback_val_t
)&nop_callback_val
;
247 if (cb
.val_del
== NULL
) {
248 cb
.val_del
= (reg_parse_callback_val_del_t
)&nop_callback_del
;
250 if (cb
.comment
== NULL
) {
252 (reg_parse_callback_comment_t
)&nop_callback_del
;
257 s
->state
= STATE_DEFAULT
;
260 if (str_enc
&& !set_iconv(&s
->str2UTF16
, "UTF-16LE", str_enc
)) {
261 DEBUG(0, ("reg_parse_new: failed to set encoding: %s\n",
266 assert(&s
->reg_format_callback
== (struct reg_format_callback
*)s
);
269 set_iconv(&s
->str2UTF16
, NULL
, NULL
);
275 * @defgroup parse Parser Primitive
281 static bool srprs_key(const char** ptr
, cbuf
* key
, bool* del
)
283 const char* pos
= *ptr
;
284 const char* closing_bracket_pos
= NULL
;
285 size_t closing_bracket_idx
= 0;
287 if (!srprs_skipws(&pos
) || !srprs_char(&pos
, '[')) {
291 *del
= srprs_char(&pos
, '-');
296 while (srprs_charsetinv(&pos
, "]\\", key
))
302 closing_bracket_idx
= cbuf_getpos(key
);
303 closing_bracket_pos
= pos
;
309 cbuf_putc(key
, '\\');
311 /* cbuf_puts(subkeyidx, cbuf_getpos(key), sizeof(size_t)) */
312 while (srprs_char(&pos
,'\\'))
317 if (closing_bracket_pos
== NULL
) {
321 /* remove trailing backslash (if any) */
322 if (*(closing_bracket_pos
-1)=='\\') {
323 closing_bracket_idx
--;
326 cbuf_setpos(key
, closing_bracket_idx
);
327 *ptr
= closing_bracket_pos
+1;
336 static bool srprs_val_name(const char** ptr
, cbuf
* name
)
338 const char* pos
= *ptr
;
339 const size_t spos
= cbuf_getpos(name
);
341 if ( !srprs_skipws(&pos
) ) {
345 if ( srprs_char(&pos
, '@') ) {
346 cbuf_puts(name
, "", -1);
348 else if (!srprs_quoted_string(&pos
, name
, NULL
)) {
352 if (!srprs_skipws(&pos
) || !srprs_char(&pos
, '=')) {
360 cbuf_setpos(name
, spos
);
364 static bool srprs_val_dword(const char** ptr
, uint32_t* type
, uint32_t* val
)
366 const char* pos
= *ptr
;
368 if (!srprs_str(&pos
, "dword:", -1)) {
372 if (!srprs_hex(&pos
, 8, val
)) {
381 static bool srprs_val_sz(const char** ptr
, uint32_t* type
, cbuf
* val
, bool* cont
)
383 if (!srprs_quoted_string(ptr
, val
, cont
)) {
392 static bool srprs_nl_no_eos(const char** ptr
, cbuf
* str
, bool eof
)
394 const char* pos
= *ptr
;
395 const size_t spos
= cbuf_getpos(str
);
397 if( srprs_nl(&pos
, str
) && (eof
|| *pos
!= '\0')) {
401 cbuf_setpos(str
, spos
);
406 static bool srprs_eol_cont(const char** ptr
, bool* cont
)
408 const char* pos
= *ptr
;
409 bool bs
= srprs_char(&pos
, '\\');
411 if (!srprs_eol(&pos
, NULL
)) {
420 /* matches the empty string, for zero length lists */
421 static bool srprs_val_hex_values(const char** ptr
, cbuf
* val
, bool* cont
)
423 const char* pos
= *ptr
;
427 if (!srprs_skipws(&pos
) || !srprs_hex(&pos
, 2, &u
) || !srprs_skipws(&pos
)) {
430 cbuf_putc(val
, (char)u
);
431 } while(srprs_char(&pos
, ','));
435 if (srprs_skipws(&pos
) && srprs_eol_cont(&pos
, cont
)) {
442 static bool srprs_val_hex(const char** ptr
, uint32_t* ptype
, cbuf
* val
,
445 const char* pos
= *ptr
;
448 if (!srprs_str(&pos
, "hex", -1)) {
452 if (srprs_char(&pos
, ':')) {
455 else if (!srprs_char(&pos
, '(') ||
456 !srprs_hex(&pos
, 8, &type
) ||
457 !srprs_char(&pos
,')') ||
458 !srprs_char(&pos
, ':'))
463 if (!srprs_val_hex_values(&pos
, val
, cont
)) {
473 static bool srprs_comment(const char** ptr
, cbuf
* str
)
475 return srprs_char(ptr
, ';') && srprs_line(ptr
, str
);
480 int reg_parse_set_options(struct reg_parse
* parser
, const char* options
)
482 static const char* DEFAULT
="enc=unix,flags=0";
486 void* ctx
= talloc_new(parser
);
488 if (options
== NULL
) {
492 while (srprs_option(&options
, ctx
, &key
, &val
)) {
493 if ((strcmp(key
, "enc") == 0) || (strcmp(key
, "strenc") == 0)) {
494 } else if ((strcmp(key
, "flags") == 0) && (val
!= NULL
)) {
497 parser
->flags
= strtol(val
, &end
, 0);
499 if ((end
==NULL
) || (*end
!= '\0')) {
500 DEBUG(0, ("Invalid flags format: %s\n",
501 val
? val
: "<NULL>"));
505 /* else if (strcmp(key, "hive") == 0) { */
506 /* if (strcmp(val, "short") == 0) { */
507 /* f->hive_fmt = REG_FMT_SHORT_HIVES; */
508 /* } else if (strcmp(val, "long") == 0) { */
509 /* f->hive_fmt = REG_FMT_LONG_HIVES; */
510 /* } else if (strcmp(val, "preserve") == 0) { */
511 /* f->hive_fmt = REG_FMT_PRESERVE_HIVES; */
513 /* DEBUG(0, ("Invalid hive format: %s\n", val)); */
523 int reg_parse_line(struct reg_parse
* parser
, const char* line
)
527 cbuf
* tmp
=cbuf_clear(parser
->tmp
);
538 switch (parser
->state
) {
539 case STATE_VAL_HEX_CONT
:
540 if (srprs_val_hex_values(&pos
, parser
->valblob
, &cont
)) {
541 cb_ok
= act_val_hex(parser
, parser
->valblob
, cont
);
544 case STATE_VAL_SZ_CONT
:
545 if (srprs_quoted_string(&pos
, parser
->valblob
, &cont
)) {
546 cb_ok
= act_val_sz(parser
, parser
->valblob
, cont
);
553 if ( !srprs_skipws(&pos
) ) {
558 if ( srprs_eol(&pos
, NULL
) ) {
563 else if (srprs_key(&pos
, tmp
, &del
)) {
564 cb_ok
= act_key(parser
, tmp
, del
);
568 else if (srprs_comment(&pos
, tmp
)) {
569 cb_ok
= act_comment(parser
, cbuf_gets(tmp
, 0));
573 else if ((parser
->linenum
== 1) && srprs_line(&pos
, tmp
) ) {
574 /* cb_ok = act_head(parser, cbuf_gets(tmp, 0)); */
578 else if (srprs_val_name(&pos
, tmp
)) {
580 cbuf_swap(parser
->valname
, tmp
);
583 if (parser
->state
!= STATE_KEY_OPEN
) {
584 DEBUG(0, ("value \"%s\" without a key at line: %i\n",
585 cbuf_gets(parser
->valname
, 0), parser
->linenum
));
589 if (!srprs_skipws(&pos
)) {
593 if (srprs_char(&pos
, '-')) {
594 cb_ok
= act_val_del(parser
);
596 else if (srprs_val_dword(&pos
, &parser
->valtype
, &dw
)) {
597 cb_ok
= act_val_dw(parser
, dw
);
599 else if (srprs_val_sz(&pos
, &parser
->valtype
, tmp
, &cont
)) {
600 cb_ok
= act_val_sz(parser
, tmp
, cont
);
602 else if (srprs_val_hex(&pos
, &parser
->valtype
, tmp
, &cont
)){
603 cb_ok
= act_val_hex(parser
, tmp
, cont
);
606 DEBUG(0, ("value \"%s\" parse error"
607 "at line: %i pos: %li : %s\n",
608 cbuf_gets(parser
->valname
, 0), parser
->linenum
,
609 (long int)(pos
-line
), pos
));
614 DEBUG(0, ("unrecognized line %i : %s\n", parser
->linenum
, line
));
622 if (!srprs_skipws(&pos
) || !srprs_eol(&pos
, NULL
)) {
623 DEBUG(0, ("trailing garbage at line: %i pos: %li : %s\n",
624 parser
->linenum
, (long int)(pos
-line
), pos
));
630 /******************************************************************************/
635 static bool lookslike_utf16(const char* line
, size_t len
, bool* little_endian
)
637 static const uint16_t M_LE
= 0xFF80;
638 static const uint16_t M_BE
= 0x80FF;
642 size_t l
= MIN(len
/2, 64);
643 const uint16_t* u
= (const uint16_t*)line
;
651 } else if ( u
[0] & M_BE
) {
658 for (i
=1; i
<l
; i
++) {
668 static bool lookslike_dos(const char* line
, size_t len
)
671 for (i
=0; i
<len
; i
++) {
672 if ( (line
[i
] == '\0') || (line
[i
] & 0x80) ) {
675 if ( (line
[i
] == '\r') && (i
+1 < len
) && (line
[i
+1] == '\n') ) {
682 static bool guess_charset(const char** ptr
,
684 const char** file_enc
,
685 const char** str_enc
)
687 const char* charset
= NULL
;
688 const char* pos
= *ptr
;
694 if (srprs_bom(&pos
, &charset
, NULL
)) {
699 declen
= (pos
- *ptr
);
705 if (*file_enc
== NULL
) {
708 else if( strcmp(*file_enc
, charset
) != 0 ) {
709 DEBUG(0, ("file encoding forced to %s\n",
713 else if (*file_enc
== NULL
) {
715 if (lookslike_utf16(*ptr
, *len
, &le
)) {
716 *file_enc
= le
? "UTF-16LE" : "UTF-16BE";
718 else if (lookslike_dos(*ptr
, *len
)) {
726 if ((str_enc
!= NULL
) && (*str_enc
== NULL
)) {
727 *str_enc
= ( strncmp(*ptr
, "REGEDIT4", 8) == 0)
736 struct reg_parse_fd_opt
{
737 const char* file_enc
;
743 static struct reg_parse_fd_opt
744 reg_parse_fd_opt(void* mem_ctx
, const char* options
)
746 struct reg_parse_fd_opt ret
= {
752 void* ctx
= talloc_new(mem_ctx
);
755 if (options
== NULL
) {
759 while (srprs_option(&options
, ctx
, &key
, &val
)) {
760 if (strcmp(key
, "enc") == 0) {
761 ret
.file_enc
= talloc_steal(mem_ctx
, val
);
762 ret
.str_enc
= ret
.file_enc
;
763 } else if (strcmp(key
, "strenc") == 0) {
764 ret
.str_enc
= talloc_steal(mem_ctx
, val
);
765 } else if (strcmp(key
, "fileenc") == 0) {
766 ret
.file_enc
= talloc_steal(mem_ctx
, val
);
767 } else if ((strcmp(key
, "flags") == 0) && (val
!= NULL
)) {
770 ret
.flags
= strtol(val
, &end
, 0);
772 if ((end
==NULL
) || (*end
!= '\0')) {
773 DEBUG(0, ("Invalid format \"%s\": %s\n",
774 key
, val
? val
: "<NULL>"));
776 } else if ((strcmp(key
, "fail") == 0) && (val
!= NULL
)) {
779 ret
.fail_level
= -strtol(val
, &end
, 0);
781 if ((end
==NULL
) || (*end
!= '\0')) {
782 DEBUG(0, ("Invalid format \"%s\": %s\n",
783 key
, val
? val
: "<NULL>"));
792 static void display_iconv_error_bytes(const char *inbuf
, size_t len
)
795 for (i
= 0; i
< 4 && i
< len
; i
++) {
796 DEBUGADD(0, ("<%02x>", (unsigned char)inbuf
[i
]));
801 int reg_parse_fd(int fd
, const struct reg_parse_callback
* cb
, const char* opts
)
803 void* mem_ctx
= talloc_stackframe();
804 cbuf
* line
= cbuf_new(mem_ctx
);
805 smb_iconv_t cd
= (smb_iconv_t
)-1;
806 struct reg_parse
* parser
= NULL
;
808 char buf_out
[1025] = { 0 };
814 size_t avail_osize
= sizeof(buf_out
)-1;
815 size_t space_to_read
= sizeof(buf_in
);
818 size_t linecount
= 0;
820 struct reg_parse_fd_opt opt
= reg_parse_fd_opt(mem_ctx
, opts
);
823 DBG_ERR("NULL callback\n");
828 nread
= read(fd
, buf_in
, space_to_read
);
830 DBG_ERR("read failed: %s\n", strerror(errno
));
843 if (!guess_charset(&iptr
, &ilen
,
844 &opt
.file_enc
, &opt
.str_enc
))
846 DBG_ERR("reg_parse_fd: failed to guess encoding\n");
852 /* File only contained charset info. */
858 DBG_DEBUG("reg_parse_fd: encoding file: %s str: %s\n",
859 opt
.file_enc
, opt
.str_enc
);
862 if (!set_iconv(&cd
, "unix", opt
.file_enc
)) {
863 DBG_ERR("reg_parse_fd: failed to set file encoding %s\n",
869 parser
= reg_parse_new(mem_ctx
, *cb
, opt
.str_enc
, opt
.flags
);
870 if (parser
== NULL
) {
875 /* Move input data to start of buf_in. */
877 memmove(buf_in
, iptr
, ilen
);
882 /* Leave last byte for null termination. */
886 * We read from buf_in (iptr), iconv converting into
895 /* We're out of possible room. */
896 DBG_ERR("no room in output buffer\n");
900 nconv
= smb_iconv(cd
, &iptr
, &ilen
, &optr
, &olen
);
901 if (nconv
== (size_t)-1) {
902 bool valid_err
= false;
903 if (errno
== EINVAL
) {
906 if (errno
== E2BIG
) {
910 DBG_ERR("smb_iconv error in file at line %zu: ",
912 display_iconv_error_bytes(iptr
, ilen
);
917 * For valid errors process the
918 * existing buffer then continue.
923 * We know this is safe as we have an extra
924 * enforced zero byte at the end of buf_out.
929 while (srprs_line(&pos
, line
) && srprs_nl_no_eos(&pos
, line
, eof
)) {
932 /* Process all lines we got. */
933 retval
= reg_parse_line(parser
, cbuf_gets(line
, 0));
934 if (retval
< opt
.fail_level
) {
935 DBG_ERR("reg_parse_line %zu fail %d\n",
946 * The output data we have
947 * processed starts at buf_out
949 * The unprocessed output
950 * data starts at pos and
953 * <------ sizeof(buf_out) - 1------------->|0|
954 * <--------- avail_osize------------------>|0|
955 * +----------------------+-------+-----------+
957 * +----------------------+-------+-----------+
962 size_t unprocessed_len
;
964 /* Paranoia checks. */
969 unprocessed_len
= optr
- pos
;
971 /* Paranoia checks. */
972 if (avail_osize
< unprocessed_len
) {
976 /* Move down any unprocessed data. */
977 memmove(buf_out
, pos
, unprocessed_len
);
980 * After the move, reset the output length.
982 * <------ sizeof(buf_out) - 1------------->|0|
983 * <--------- avail_osize------------------>|0|
984 * +----------------------+-------+-----------+
986 * +----------------------+-------+-----------+
991 optr
= buf_out
+ unprocessed_len
;
993 * Calculate the new output space available
995 * We already did the paranoia check for this
998 olen
= avail_osize
- unprocessed_len
;
1002 * Move any unprocessed data to the start of
1003 * the input buffer (buf_in).
1005 if (ilen
> 0 && iptr
> buf_in
) {
1006 memmove(buf_in
, iptr
, ilen
);
1009 /* Is there any space to read more input ? */
1010 if (ilen
>= sizeof(buf_in
)) {
1011 /* No space. Nothing was converted. Error. */
1012 DBG_ERR("no space in input buffer\n");
1017 space_to_read
= sizeof(buf_in
) - ilen
;
1019 /* Read the next chunk from the file. */
1020 nread
= read(fd
, buf_in
+ ilen
, space_to_read
);
1022 DBG_ERR("read failed: %s\n", strerror(errno
));
1032 /* Paranoia check. */
1033 if (nread
+ ilen
< ilen
) {
1038 /* Paranoia check. */
1039 if (nread
+ ilen
> sizeof(buf_in
)) {
1045 ilen
= nread
+ ilen
;
1052 set_iconv(&cd
, NULL
, NULL
);
1054 set_iconv(&parser
->str2UTF16
, NULL
, NULL
);
1056 talloc_free(mem_ctx
);
1060 int reg_parse_file(const char* fname
, const struct reg_parse_callback
* cb
,
1066 fd
= open(fname
, O_RDONLY
);
1068 DEBUG(0, ("reg_parse_file: open %s failed: %s\n", fname
,
1073 ret
= reg_parse_fd(fd
, cb
, opt
);
1079 /* static struct registry_key *find_regkey_by_hnd(pipes_struct *p, */
1080 /* struct policy_handle *hnd) */
1082 /* struct registry_key *regkey = NULL; */
1084 /* if(!find_policy_by_hnd(p,hnd,(void **)(void *)®key)) { */
1085 /* DEBUG(2,("find_regkey_index_by_hnd: Registry Key not found: ")); */
1089 /* return regkey; */