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"));
126 return value_callback(p
);
131 static bool act_val_dw(struct reg_parse
* p
, uint32_t val
)
133 assert(p
->valtype
== REG_DWORD
);
134 assert(p
->state
== STATE_KEY_OPEN
);
136 cbuf_clear(p
->valblob
);
138 if (cbuf_putdw(p
->valblob
, val
) < 0) {
141 return value_callback(p
);
144 static bool act_val_sz(struct reg_parse
* p
, cbuf
* value
, bool cont
)
146 cbuf_swap(p
->valblob
, value
);
148 assert(p
->valtype
== REG_SZ
);
149 assert((p
->state
== STATE_KEY_OPEN
) || (p
->state
== STATE_VAL_SZ_CONT
));
152 p
->state
= STATE_VAL_SZ_CONT
;
156 const char* src
= cbuf_gets(p
->valblob
, 0);
158 p
->state
= STATE_KEY_OPEN
;
161 if (convert_string_talloc(p
->valblob
, CH_UNIX
, CH_UTF16LE
,
165 cbuf_swapptr(p
->valblob
, &dst
, dlen
);
167 DEBUG(0, ("convert_string_talloc failed: >%s<\n"
168 "use it as is\t", src
));
172 return value_callback(p
);
177 static bool act_val_del(struct reg_parse
* p
)
179 const char* name
= cbuf_gets(p
->valname
, 0);
181 assert(p
->call
.val_del
);
182 p
->ret
= p
->call
.val_del(p
->call
.data
, name
);
186 static bool act_comment (struct reg_parse
* p
, const char* txt
)
188 assert(p
->call
.comment
);
189 p
->ret
= p
->call
.comment(p
->call
.data
, txt
);
195 static int nop(void* data
)
201 struct reg_parse
* reg_parse_new(const void* ctx
,
202 struct reg_parse_callback cb
,
203 const char* str_enc
, unsigned flags
)
205 struct reg_parse
* s
= talloc_zero(ctx
, struct reg_parse
);
208 s
->key
= cbuf_new(s
);
209 s
->valname
= cbuf_new(s
);
210 s
->valblob
= cbuf_new(s
);
211 s
->tmp
= cbuf_new(s
);
212 if ( (s
->tmp
== NULL
) || (s
->valblob
== NULL
)
213 || (s
->valname
== NULL
) || (s
->key
== NULL
) )
218 s
->reg_format_callback
.writeline
= (reg_format_callback_writeline_t
)®_parse_line
;
219 s
->reg_format_callback
.data
= s
;
222 if (cb
.key
== NULL
) {
223 cb
.key
= (reg_parse_callback_key_t
)&nop
;
225 if (cb
.val
== NULL
) {
226 cb
.val
= (reg_parse_callback_val_t
)&nop
;
228 if (cb
.val_del
== NULL
) {
229 cb
.val_del
= (reg_parse_callback_val_del_t
)&nop
;
231 if (cb
.comment
== NULL
) {
232 cb
.comment
= (reg_parse_callback_comment_t
)&nop
;
237 s
->state
= STATE_DEFAULT
;
240 if (str_enc
&& !set_iconv(&s
->str2UTF16
, "UTF-16LE", str_enc
)) {
241 DEBUG(0, ("reg_parse_new: failed to set encoding: %s",
246 assert(&s
->reg_format_callback
== (struct reg_format_callback
*)s
);
254 * @defgroup parse Parser Primitive
260 static bool srprs_key(const char** ptr
, cbuf
* key
, bool* del
)
262 const char* pos
= *ptr
;
263 const char* closing_bracket_pos
= NULL
;
264 size_t closing_bracket_idx
= 0;
266 if (!srprs_skipws(&pos
) || !srprs_char(&pos
, '[')) {
270 *del
= srprs_char(&pos
, '-');
275 while (srprs_charsetinv(&pos
, "]\\", key
))
281 closing_bracket_idx
= cbuf_getpos(key
);
282 closing_bracket_pos
= pos
;
288 cbuf_putc(key
, '\\');
290 /* cbuf_puts(subkeyidx, cbuf_getpos(key), sizeof(size_t)) */
291 while (srprs_char(&pos
,'\\'))
296 if (closing_bracket_pos
== NULL
) {
300 /* remove trailing backslash (if any) */
301 if (*(closing_bracket_pos
-1)=='\\') {
302 closing_bracket_idx
--;
305 cbuf_setpos(key
, closing_bracket_idx
);
306 *ptr
= closing_bracket_pos
+1;
315 static bool srprs_val_name(const char** ptr
, cbuf
* name
)
317 const char* pos
= *ptr
;
318 const size_t spos
= cbuf_getpos(name
);
320 if ( !srprs_skipws(&pos
) ) {
324 if ( srprs_char(&pos
, '@') ) {
325 cbuf_puts(name
, "", -1);
327 else if (!srprs_quoted_string(&pos
, name
, NULL
)) {
331 if (!srprs_skipws(&pos
) || !srprs_char(&pos
, '=')) {
339 cbuf_setpos(name
, spos
);
343 static bool srprs_val_dword(const char** ptr
, uint32_t* type
, uint32_t* val
)
345 const char* pos
= *ptr
;
347 if (!srprs_str(&pos
, "dword:", -1)) {
351 if (!srprs_hex(&pos
, 8, val
)) {
360 static bool srprs_val_sz(const char** ptr
, uint32_t* type
, cbuf
* val
, bool* cont
)
362 if (!srprs_quoted_string(ptr
, val
, cont
)) {
371 static bool srprs_nl_no_eos(const char** ptr
, cbuf
* str
, bool eof
)
373 const char* pos
= *ptr
;
374 const size_t spos
= cbuf_getpos(str
);
376 if( srprs_nl(&pos
, str
) && (eof
|| *pos
!= '\0')) {
380 cbuf_setpos(str
, spos
);
385 static bool srprs_eol_cont(const char** ptr
, bool* cont
)
387 const char* pos
= *ptr
;
388 bool bs
= srprs_char(&pos
, '\\');
390 if (!srprs_eol(&pos
, NULL
)) {
399 /* matches the empty string, for zero length lists */
400 static bool srprs_val_hex_values(const char** ptr
, cbuf
* val
, bool* cont
)
402 const char* pos
= *ptr
;
406 if (!srprs_skipws(&pos
) || !srprs_hex(&pos
, 2, &u
) || !srprs_skipws(&pos
)) {
409 cbuf_putc(val
, (char)u
);
410 } while(srprs_char(&pos
, ','));
414 if (srprs_skipws(&pos
) && srprs_eol_cont(&pos
, cont
)) {
421 static bool srprs_val_hex(const char** ptr
, uint32_t* ptype
, cbuf
* val
,
424 const char* pos
= *ptr
;
427 if (!srprs_str(&pos
, "hex", -1)) {
431 if (srprs_char(&pos
, ':')) {
434 else if (!srprs_char(&pos
, '(') ||
435 !srprs_hex(&pos
, 8, &type
) ||
436 !srprs_char(&pos
,')') ||
437 !srprs_char(&pos
, ':'))
442 if (!srprs_val_hex_values(&pos
, val
, cont
)) {
452 static bool srprs_comment(const char** ptr
, cbuf
* str
)
454 return srprs_char(ptr
, ';') && srprs_line(ptr
, str
);
459 int reg_parse_set_options(struct reg_parse
* parser
, const char* options
)
461 static const char* DEFAULT
="enc=unix,flags=0";
465 void* ctx
= talloc_new(parser
);
467 if (options
== NULL
) {
471 while (srprs_option(&options
, ctx
, &key
, &val
)) {
472 if ((strcmp(key
, "enc") == 0) || (strcmp(key
, "strenc") == 0)) {
473 } else if ((strcmp(key
, "flags") == 0) && (val
!= NULL
)) {
476 parser
->flags
= strtol(val
, &end
, 0);
478 if ((end
==NULL
) || (*end
!= '\0')) {
479 DEBUG(0, ("Invalid flags format: %s\n",
480 val
? val
: "<NULL>"));
484 /* else if (strcmp(key, "hive") == 0) { */
485 /* if (strcmp(val, "short") == 0) { */
486 /* f->hive_fmt = REG_FMT_SHORT_HIVES; */
487 /* } else if (strcmp(val, "long") == 0) { */
488 /* f->hive_fmt = REG_FMT_LONG_HIVES; */
489 /* } else if (strcmp(val, "preserve") == 0) { */
490 /* f->hive_fmt = REG_FMT_PRESERVE_HIVES; */
492 /* DEBUG(0, ("Invalid hive format: %s\n", val)); */
502 int reg_parse_line(struct reg_parse
* parser
, const char* line
)
506 cbuf
* tmp
=cbuf_clear(parser
->tmp
);
517 switch (parser
->state
) {
518 case STATE_VAL_HEX_CONT
:
519 if (srprs_val_hex_values(&pos
, parser
->valblob
, &cont
)) {
520 cb_ok
= act_val_hex(parser
, parser
->valblob
, cont
);
523 case STATE_VAL_SZ_CONT
:
524 if (srprs_quoted_string(&pos
, parser
->valblob
, &cont
)) {
525 cb_ok
= act_val_sz(parser
, parser
->valblob
, cont
);
532 if ( !srprs_skipws(&pos
) ) {
537 if ( srprs_eol(&pos
, NULL
) ) {
542 else if (srprs_key(&pos
, tmp
, &del
)) {
543 cb_ok
= act_key(parser
, tmp
, del
);
547 else if (srprs_comment(&pos
, tmp
)) {
548 cb_ok
= act_comment(parser
, cbuf_gets(tmp
, 0));
552 else if ((parser
->linenum
== 1) && srprs_line(&pos
, tmp
) ) {
553 /* cb_ok = act_head(parser, cbuf_gets(tmp, 0)); */
557 else if (srprs_val_name(&pos
, tmp
)) {
559 cbuf_swap(parser
->valname
, tmp
);
562 if (parser
->state
!= STATE_KEY_OPEN
) {
563 DEBUG(0, ("value \"%s\" without a key at line: %i",
564 cbuf_gets(parser
->valname
, 0), parser
->linenum
));
568 if (!srprs_skipws(&pos
)) {
572 if (srprs_char(&pos
, '-')) {
573 cb_ok
= act_val_del(parser
);
575 else if (srprs_val_dword(&pos
, &parser
->valtype
, &dw
)) {
576 cb_ok
= act_val_dw(parser
, dw
);
578 else if (srprs_val_sz(&pos
, &parser
->valtype
, tmp
, &cont
)) {
579 cb_ok
= act_val_sz(parser
, tmp
, cont
);
581 else if (srprs_val_hex(&pos
, &parser
->valtype
, tmp
, &cont
)){
582 cb_ok
= act_val_hex(parser
, tmp
, cont
);
585 DEBUG(0, ("value \"%s\" parse error"
586 "at line: %i pos: %li : %s",
587 cbuf_gets(parser
->valname
, 0), parser
->linenum
,
588 (long int)(pos
-line
), pos
));
593 DEBUG(0, ("unrecognized line %i : %s\n", parser
->linenum
, line
));
601 if (!srprs_skipws(&pos
) || !srprs_eol(&pos
, NULL
)) {
602 DEBUG(0, ("trailing garbage at line: %i pos: %li : %s\n",
603 parser
->linenum
, (long int)(pos
-line
), pos
));
609 /******************************************************************************/
614 static bool lookslike_utf16(const char* line
, size_t len
, bool* little_endian
)
616 static const uint16_t M_LE
= 0xFF80;
617 static const uint16_t M_BE
= 0x80FF;
621 size_t l
= MIN(len
/2, 64);
622 const uint16_t* u
= (const uint16_t*)line
;
630 } else if ( u
[0] & M_BE
) {
637 for (i
=1; i
<l
; i
++) {
647 static bool lookslike_dos(const char* line
, size_t len
)
650 for (i
=0; i
<len
; i
++) {
651 if ( (line
[i
] == '\0') || (line
[i
] & 0x80) ) {
654 if ( (line
[i
] == '\r') && (i
+1 < len
) && (line
[i
+1] == '\n') ) {
661 static bool guess_charset(const char** ptr
,
663 const char** file_enc
,
664 const char** str_enc
)
666 const char* charset
= NULL
;
667 const char* pos
= *ptr
;
673 if (srprs_bom(&pos
, &charset
, NULL
)) {
674 *len
-= (pos
- *ptr
);
676 if (*file_enc
== NULL
) {
679 else if( strcmp(*file_enc
, charset
) != 0 ) {
680 DEBUG(0, ("file encoding forced to %s\n",
684 else if (*file_enc
== NULL
) {
686 if (lookslike_utf16(*ptr
, *len
, &le
)) {
687 *file_enc
= le
? "UTF-16LE" : "UTF-16BE";
689 else if (lookslike_dos(*ptr
, *len
)) {
697 if ((str_enc
!= NULL
) && (*str_enc
== NULL
)) {
698 *str_enc
= ( strncmp(*ptr
, "REGEDIT4", 8) == 0)
707 struct reg_parse_fd_opt
{
708 const char* file_enc
;
714 static struct reg_parse_fd_opt
715 reg_parse_fd_opt(void* mem_ctx
, const char* options
)
717 struct reg_parse_fd_opt ret
= {
723 void* ctx
= talloc_new(mem_ctx
);
726 if (options
== NULL
) {
730 while (srprs_option(&options
, ctx
, &key
, &val
)) {
731 if (strcmp(key
, "enc") == 0) {
732 ret
.file_enc
= talloc_steal(mem_ctx
, val
);
733 ret
.str_enc
= ret
.file_enc
;
734 } else if (strcmp(key
, "strenc") == 0) {
735 ret
.str_enc
= talloc_steal(mem_ctx
, val
);
736 } else if (strcmp(key
, "fileenc") == 0) {
737 ret
.file_enc
= talloc_steal(mem_ctx
, val
);
738 } else if ((strcmp(key
, "flags") == 0) && (val
!= NULL
)) {
741 ret
.flags
= strtol(val
, &end
, 0);
743 if ((end
==NULL
) || (*end
!= '\0')) {
744 DEBUG(0, ("Invalid format \"%s\": %s\n",
745 key
, val
? val
: "<NULL>"));
747 } else if ((strcmp(key
, "fail") == 0) && (val
!= NULL
)) {
750 ret
.fail_level
= -strtol(val
, &end
, 0);
752 if ((end
==NULL
) || (*end
!= '\0')) {
753 DEBUG(0, ("Invalid format \"%s\": %s\n",
754 key
, val
? val
: "<NULL>"));
765 handle_iconv_errno(int err
, const char* obuf
, size_t linenum
,
766 smb_iconv_t cd
, const char** iptr
, size_t* ilen
,
767 char** optr
, size_t *olen
)
769 const char *pos
= obuf
;
770 const char *ptr
= obuf
;
773 /* DEBUG(0, ("Incomplete multibyte sequence\n")); */
783 while (srprs_line(&ptr
, NULL
) && srprs_nl(&ptr
, NULL
)) {
788 pos
= MAX(obuf
, *optr
-60);
790 DEBUG(0, ("Illegal multibyte sequence at line %lu: %s",
791 (long unsigned)(linenum
+1), pos
));
796 DEBUGADD(0, ("<%02x>", (unsigned char)**iptr
));
801 /* Todo: parametrize, e.g. skip: *optr++ = *iptr++; */
805 if (smb_iconv(cd
, iptr
, &il
, optr
, olen
) != (size_t)-1 || (errno
!= EILSEQ
)) {
812 while ((*ilen
> 0) && (*olen
> 0));
818 int reg_parse_fd(int fd
, const struct reg_parse_callback
* cb
, const char* opts
)
820 void* mem_ctx
= talloc_stackframe();
821 cbuf
* line
= cbuf_new(mem_ctx
);
822 smb_iconv_t cd
= (smb_iconv_t
)-1;
823 struct reg_parse
* parser
= NULL
;
838 struct reg_parse_fd_opt opt
= reg_parse_fd_opt(mem_ctx
, opts
);
841 DEBUG(0,("reg_parse_fd: NULL callback\n"));
845 nread
= read(fd
, buf_raw
, sizeof(buf_raw
));
847 DEBUG(0, ("reg_parse_fd: read failed: %s\n", strerror(errno
)));
855 if (!guess_charset(&iptr
, &ilen
,
856 &opt
.file_enc
, &opt
.str_enc
))
858 DEBUG(0, ("reg_parse_fd: failed to guess encoding\n"));
862 DEBUG(10, ("reg_parse_fd: encoding file: %s str: %s\n",
863 opt
.file_enc
, opt
.str_enc
));
866 if (!set_iconv(&cd
, "unix", opt
.file_enc
)) {
867 DEBUG(0, ("reg_parse_fd: failed to set file encoding %s\n",
872 parser
= reg_parse_new(mem_ctx
, *cb
, opt
.str_enc
, opt
.flags
);
876 olen
= sizeof(buf_unix
) - (optr
- buf_unix
) - 1 ;
878 memmove(buf_raw
, iptr
, ilen
);
880 nread
= read(fd
, buf_raw
+ ilen
, sizeof(buf_raw
) - ilen
);
882 DEBUG(0, ("reg_parse_fd: read failed: %s\n", strerror(errno
)));
891 smb_iconv(cd
, NULL
, NULL
, &optr
, &olen
);
896 nconv
= smb_iconv(cd
, &iptr
, &ilen
, &optr
, &olen
);
898 if (nconv
== (size_t)-1) {
899 handle_iconv_errno(errno
, buf_unix
, linenum
,
909 while ( srprs_line(&pos
, line
) && srprs_nl_no_eos(&pos
, line
, eof
)) {
911 ret
= reg_parse_line(parser
, cbuf_gets(line
, 0));
912 if (ret
< opt
.fail_level
) {
917 memmove(buf_unix
, pos
, optr
- pos
);
918 optr
-= (pos
- buf_unix
);
923 set_iconv(&cd
, NULL
, NULL
);
924 talloc_free(mem_ctx
);
928 int reg_parse_file(const char* fname
, const struct reg_parse_callback
* cb
,
934 fd
= open(fname
, O_RDONLY
);
936 DEBUG(0, ("reg_parse_file: open %s failed: %s\n", fname
,
941 ret
= reg_parse_fd(fd
, cb
, opt
);
947 /* static struct registry_key *find_regkey_by_hnd(pipes_struct *p, */
948 /* struct policy_handle *hnd) */
950 /* struct registry_key *regkey = NULL; */
952 /* if(!find_policy_by_hnd(p,hnd,(void **)(void *)®key)) { */
953 /* DEBUG(2,("find_regkey_index_by_hnd: Registry Key not found: ")); */