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"
42 #include <sys/types.h>
47 enum reg_parse_state
{
55 struct reg_format_callback reg_format_callback
;
61 struct reg_parse_callback call
;
64 enum reg_parse_state state
;
65 struct reg_parse_options
* opt
;
66 smb_iconv_t str2UTF16
;
71 * @defgroup action Action
74 static bool act_key(struct reg_parse
* p
, cbuf
* keyname
, bool del
)
76 const char* name
= cbuf_gets(keyname
, 0);
77 cbuf_swap(p
->key
, keyname
);
79 assert(p
->state
== STATE_DEFAULT
|| p
->state
== STATE_KEY_OPEN
);
80 p
->state
= del
? STATE_DEFAULT
: STATE_KEY_OPEN
;
83 p
->ret
= p
->call
.key(p
->call
.data
, &name
, 1, del
);
87 static bool value_callback(struct reg_parse
* p
)
89 const char* name
= cbuf_gets(p
->valname
,0);
90 const uint8_t* val
= (const uint8_t*)cbuf_gets(p
->valblob
,0);
91 size_t len
= cbuf_getpos(p
->valblob
);
94 p
->ret
= p
->call
.val(p
->call
.data
, name
, p
->valtype
, val
, len
);
98 static bool act_val_hex(struct reg_parse
* p
, cbuf
* value
, bool cont
)
100 cbuf_swap(p
->valblob
, value
);
101 assert((p
->state
== STATE_KEY_OPEN
) || (p
->state
== STATE_VAL_HEX_CONT
));
104 p
->state
= STATE_VAL_HEX_CONT
;
106 p
->state
= STATE_KEY_OPEN
;
108 switch (p
->valtype
) {
111 if (p
->str2UTF16
!= NULL
) {
113 const char* src
= cbuf_gets(p
->valblob
, 0);
114 const size_t slen
= cbuf_getpos(p
->valblob
);
115 size_t dlen
= iconvert_talloc(p
,
120 cbuf_swapptr(p
->valblob
, &dst
, dlen
);
122 DEBUG(0, ("iconvert_talloc failed\n"));
129 return value_callback(p
);
134 static bool act_val_dw(struct reg_parse
* p
, uint32_t val
)
136 assert(p
->valtype
== REG_DWORD
);
137 assert(p
->state
== STATE_KEY_OPEN
);
139 cbuf_clear(p
->valblob
);
141 if (cbuf_putdw(p
->valblob
, val
) < 0) {
144 return value_callback(p
);
147 static bool act_val_sz(struct reg_parse
* p
, cbuf
* value
, bool cont
)
149 cbuf_swap(p
->valblob
, value
);
151 assert(p
->valtype
== REG_SZ
);
152 assert((p
->state
== STATE_KEY_OPEN
) || (p
->state
== STATE_VAL_SZ_CONT
));
155 p
->state
= STATE_VAL_SZ_CONT
;
159 const char* src
= cbuf_gets(p
->valblob
, 0);
161 p
->state
= STATE_KEY_OPEN
;
164 if (convert_string_talloc(p
->valblob
, CH_UNIX
, CH_UTF16LE
,
168 cbuf_swapptr(p
->valblob
, &dst
, dlen
);
170 DEBUG(0, ("convert_string_talloc failed: >%s<\n"
171 "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(void* data
)
204 struct reg_parse
* reg_parse_new(const void* ctx
,
205 struct reg_parse_callback cb
,
206 const char* str_enc
, unsigned flags
)
208 struct reg_parse
* s
= talloc_zero(ctx
, struct reg_parse
);
211 s
->key
= cbuf_new(s
);
212 s
->valname
= cbuf_new(s
);
213 s
->valblob
= cbuf_new(s
);
214 s
->tmp
= cbuf_new(s
);
215 if ( (s
->tmp
== NULL
) || (s
->valblob
== NULL
)
216 || (s
->valname
== NULL
) || (s
->key
== NULL
) )
221 s
->reg_format_callback
.writeline
= (reg_format_callback_writeline_t
)®_parse_line
;
222 s
->reg_format_callback
.data
= s
;
225 if (cb
.key
== NULL
) {
226 cb
.key
= (reg_parse_callback_key_t
)&nop
;
228 if (cb
.val
== NULL
) {
229 cb
.val
= (reg_parse_callback_val_t
)&nop
;
231 if (cb
.val_del
== NULL
) {
232 cb
.val_del
= (reg_parse_callback_val_del_t
)&nop
;
234 if (cb
.comment
== NULL
) {
235 cb
.comment
= (reg_parse_callback_comment_t
)&nop
;
240 s
->state
= STATE_DEFAULT
;
243 if (str_enc
&& !set_iconv(&s
->str2UTF16
, "UTF-16LE", str_enc
)) {
244 DEBUG(0, ("reg_parse_new: failed to set encoding: %s",
249 assert(&s
->reg_format_callback
== (struct reg_format_callback
*)s
);
257 * @defgroup parse Parser Primitive
263 static bool srprs_key(const char** ptr
, cbuf
* key
, bool* del
)
265 const char* pos
= *ptr
;
266 const char* closing_bracket_pos
= NULL
;
267 size_t closing_bracket_idx
= 0;
269 if (!srprs_skipws(&pos
) || !srprs_char(&pos
, '[')) {
273 *del
= srprs_char(&pos
, '-');
278 while (srprs_charsetinv(&pos
, "]\\", key
))
284 closing_bracket_idx
= cbuf_getpos(key
);
285 closing_bracket_pos
= pos
;
291 cbuf_putc(key
, '\\');
293 /* cbuf_puts(subkeyidx, cbuf_getpos(key), sizeof(size_t)) */
294 while (srprs_char(&pos
,'\\'))
299 if (closing_bracket_pos
== NULL
) {
303 /* remove trailing backslash (if any) */
304 if (*(closing_bracket_pos
-1)=='\\') {
305 closing_bracket_idx
--;
308 cbuf_setpos(key
, closing_bracket_idx
);
309 *ptr
= closing_bracket_pos
+1;
318 static bool srprs_val_name(const char** ptr
, cbuf
* name
)
320 const char* pos
= *ptr
;
321 const size_t spos
= cbuf_getpos(name
);
323 if ( !srprs_skipws(&pos
) ) {
327 if ( srprs_char(&pos
, '@') ) {
328 cbuf_puts(name
, "", -1);
330 else if (!srprs_quoted_string(&pos
, name
, NULL
)) {
334 if (!srprs_skipws(&pos
) || !srprs_char(&pos
, '=')) {
342 cbuf_setpos(name
, spos
);
346 static bool srprs_val_dword(const char** ptr
, uint32_t* type
, uint32_t* val
)
348 const char* pos
= *ptr
;
350 if (!srprs_str(&pos
, "dword:", -1)) {
354 if (!srprs_hex(&pos
, 8, val
)) {
363 static bool srprs_val_sz(const char** ptr
, uint32_t* type
, cbuf
* val
, bool* cont
)
365 if (!srprs_quoted_string(ptr
, val
, cont
)) {
374 static bool srprs_nl_no_eos(const char** ptr
, cbuf
* str
, bool eof
)
376 const char* pos
= *ptr
;
377 const size_t spos
= cbuf_getpos(str
);
379 if( srprs_nl(&pos
, str
) && (eof
|| *pos
!= '\0')) {
383 cbuf_setpos(str
, spos
);
388 static bool srprs_eol_cont(const char** ptr
, bool* cont
)
390 const char* pos
= *ptr
;
391 bool bs
= srprs_char(&pos
, '\\');
393 if (!srprs_eol(&pos
, NULL
)) {
402 /* matches the empty string, for zero length lists */
403 static bool srprs_val_hex_values(const char** ptr
, cbuf
* val
, bool* cont
)
405 const char* pos
= *ptr
;
409 if (!srprs_skipws(&pos
) || !srprs_hex(&pos
, 2, &u
) || !srprs_skipws(&pos
)) {
412 cbuf_putc(val
, (char)u
);
413 } while(srprs_char(&pos
, ','));
417 if (srprs_skipws(&pos
) && srprs_eol_cont(&pos
, cont
)) {
424 static bool srprs_val_hex(const char** ptr
, uint32_t* ptype
, cbuf
* val
,
427 const char* pos
= *ptr
;
430 if (!srprs_str(&pos
, "hex", -1)) {
434 if (srprs_char(&pos
, ':')) {
437 else if (!srprs_char(&pos
, '(') ||
438 !srprs_hex(&pos
, 8, &type
) ||
439 !srprs_char(&pos
,')') ||
440 !srprs_char(&pos
, ':'))
445 if (!srprs_val_hex_values(&pos
, val
, cont
)) {
455 static bool srprs_comment(const char** ptr
, cbuf
* str
)
457 return srprs_char(ptr
, ';') && srprs_line(ptr
, str
);
462 int reg_parse_set_options(struct reg_parse
* parser
, const char* options
)
464 static const char* DEFAULT
="enc=unix,flags=0";
468 void* ctx
= talloc_new(parser
);
470 if (options
== NULL
) {
474 while (srprs_option(&options
, ctx
, &key
, &val
)) {
475 if ((strcmp(key
, "enc") == 0) || (strcmp(key
, "strenc") == 0)) {
476 } else if ((strcmp(key
, "flags") == 0) && (val
!= NULL
)) {
479 parser
->flags
= strtol(val
, &end
, 0);
481 if ((end
==NULL
) || (*end
!= '\0')) {
482 DEBUG(0, ("Invalid flags format: %s\n",
483 val
? val
: "<NULL>"));
487 /* else if (strcmp(key, "hive") == 0) { */
488 /* if (strcmp(val, "short") == 0) { */
489 /* f->hive_fmt = REG_FMT_SHORT_HIVES; */
490 /* } else if (strcmp(val, "long") == 0) { */
491 /* f->hive_fmt = REG_FMT_LONG_HIVES; */
492 /* } else if (strcmp(val, "preserve") == 0) { */
493 /* f->hive_fmt = REG_FMT_PRESERVE_HIVES; */
495 /* DEBUG(0, ("Invalid hive format: %s\n", val)); */
505 int reg_parse_line(struct reg_parse
* parser
, const char* line
)
509 cbuf
* tmp
=cbuf_clear(parser
->tmp
);
520 switch (parser
->state
) {
521 case STATE_VAL_HEX_CONT
:
522 if (srprs_val_hex_values(&pos
, parser
->valblob
, &cont
)) {
523 cb_ok
= act_val_hex(parser
, parser
->valblob
, cont
);
526 case STATE_VAL_SZ_CONT
:
527 if (srprs_quoted_string(&pos
, parser
->valblob
, &cont
)) {
528 cb_ok
= act_val_sz(parser
, parser
->valblob
, cont
);
535 if ( !srprs_skipws(&pos
) ) {
540 if ( srprs_eol(&pos
, NULL
) ) {
545 else if (srprs_key(&pos
, tmp
, &del
)) {
546 cb_ok
= act_key(parser
, tmp
, del
);
550 else if (srprs_comment(&pos
, tmp
)) {
551 cb_ok
= act_comment(parser
, cbuf_gets(tmp
, 0));
555 else if ((parser
->linenum
== 1) && srprs_line(&pos
, tmp
) ) {
556 /* cb_ok = act_head(parser, cbuf_gets(tmp, 0)); */
560 else if (srprs_val_name(&pos
, tmp
)) {
562 cbuf_swap(parser
->valname
, tmp
);
565 if (parser
->state
!= STATE_KEY_OPEN
) {
566 DEBUG(0, ("value \"%s\" without a key at line: %i",
567 cbuf_gets(parser
->valname
, 0), parser
->linenum
));
571 if (!srprs_skipws(&pos
)) {
575 if (srprs_char(&pos
, '-')) {
576 cb_ok
= act_val_del(parser
);
578 else if (srprs_val_dword(&pos
, &parser
->valtype
, &dw
)) {
579 cb_ok
= act_val_dw(parser
, dw
);
581 else if (srprs_val_sz(&pos
, &parser
->valtype
, tmp
, &cont
)) {
582 cb_ok
= act_val_sz(parser
, tmp
, cont
);
584 else if (srprs_val_hex(&pos
, &parser
->valtype
, tmp
, &cont
)){
585 cb_ok
= act_val_hex(parser
, tmp
, cont
);
588 DEBUG(0, ("value \"%s\" parse error"
589 "at line: %i pos: %li : %s",
590 cbuf_gets(parser
->valname
, 0), parser
->linenum
,
591 (long int)(pos
-line
), pos
));
596 DEBUG(0, ("unrecognized line %i : %s\n", parser
->linenum
, line
));
604 if (!srprs_skipws(&pos
) || !srprs_eol(&pos
, NULL
)) {
605 DEBUG(0, ("trailing garbage at line: %i pos: %li : %s\n",
606 parser
->linenum
, (long int)(pos
-line
), pos
));
612 /******************************************************************************/
617 static bool lookslike_utf16(const char* line
, size_t len
, bool* little_endian
)
619 static const uint16_t M_LE
= 0xFF80;
620 static const uint16_t M_BE
= 0x80FF;
624 size_t l
= MIN(len
/2, 64);
625 uint16_t* u
= (uint16_t*)line
;
633 } else if ( u
[0] & M_BE
) {
640 for (i
=1; i
<l
; i
++) {
650 static bool lookslike_dos(const char* line
, size_t len
)
653 for (i
=0; i
<len
; i
++) {
654 if ( (line
[i
] == '\0') || (line
[i
] & 0x80) ) {
657 if ( (line
[i
] == '\r') && (i
+1 < len
) && (line
[i
+1] == '\n') ) {
664 static bool guess_charset(const char** ptr
,
666 const char** file_enc
,
667 const char** str_enc
)
669 const char* charset
= NULL
;
670 const char* pos
= *ptr
;
676 if (srprs_bom(&pos
, &charset
, NULL
)) {
677 *len
-= (pos
- *ptr
);
679 if (*file_enc
== NULL
) {
682 else if( strcmp(*file_enc
, charset
) != 0 ) {
683 DEBUG(0, ("file encoding forced to %s\n",
687 else if (*file_enc
== NULL
) {
689 if (lookslike_utf16(*ptr
, *len
, &le
)) {
690 *file_enc
= le
? "UTF-16LE" : "UTF-16BE";
692 else if (lookslike_dos(*ptr
, *len
)) {
700 if ((str_enc
!= NULL
) && (*str_enc
== NULL
)) {
701 *str_enc
= ( strncmp(*ptr
, "REGEDIT4", 8) == 0)
710 struct reg_parse_fd_opt
{
711 const char* file_enc
;
717 static struct reg_parse_fd_opt
718 reg_parse_fd_opt(void* mem_ctx
, const char* options
)
720 struct reg_parse_fd_opt ret
= {
726 void* ctx
= talloc_new(mem_ctx
);
729 if (options
== NULL
) {
733 while (srprs_option(&options
, ctx
, &key
, &val
)) {
734 if (strcmp(key
, "enc") == 0) {
735 ret
.file_enc
= talloc_steal(mem_ctx
, val
);
736 ret
.str_enc
= ret
.file_enc
;
737 } else if (strcmp(key
, "strenc") == 0) {
738 ret
.str_enc
= talloc_steal(mem_ctx
, val
);
739 } else if (strcmp(key
, "fileenc") == 0) {
740 ret
.file_enc
= talloc_steal(mem_ctx
, val
);
741 } else if ((strcmp(key
, "flags") == 0) && (val
!= NULL
)) {
744 ret
.flags
= strtol(val
, &end
, 0);
746 if ((end
==NULL
) || (*end
!= '\0')) {
747 DEBUG(0, ("Invalid format \"%s\": %s\n",
748 key
, val
? val
: "<NULL>"));
750 } else if ((strcmp(key
, "fail") == 0) && (val
!= NULL
)) {
753 ret
.fail_level
= -strtol(val
, &end
, 0);
755 if ((end
==NULL
) || (*end
!= '\0')) {
756 DEBUG(0, ("Invalid format \"%s\": %s\n",
757 key
, val
? val
: "<NULL>"));
768 handle_iconv_errno(int err
, const char* obuf
, size_t linenum
,
769 smb_iconv_t cd
, const char** iptr
, size_t* ilen
,
770 char** optr
, size_t *olen
)
772 const char *pos
= obuf
;
773 const char *ptr
= obuf
;
776 /* DEBUG(0, ("Incomplete multibyte sequence\n")); */
786 while (srprs_line(&ptr
, NULL
) && srprs_nl(&ptr
, NULL
)) {
791 pos
= MAX(obuf
, *optr
-60);
793 DEBUG(0, ("Illegal multibyte sequence at line %lu: %s",
794 (long unsigned)(linenum
+1), pos
));
799 DEBUGADD(0, ("<%02x>", (unsigned char)**iptr
));
804 /* Todo: parametrize, e.g. skip: *optr++ = *iptr++; */
808 if (smb_iconv(cd
, iptr
, &il
, optr
, olen
) != (size_t)-1 || (errno
!= EILSEQ
)) {
815 while ((*ilen
> 0) && (*olen
> 0));
821 int reg_parse_fd(int fd
, const struct reg_parse_callback
* cb
, const char* opts
)
823 void* mem_ctx
= talloc_stackframe();
824 cbuf
* line
= cbuf_new(mem_ctx
);
825 smb_iconv_t cd
= (smb_iconv_t
)-1;
826 struct reg_parse
* parser
= NULL
;
841 struct reg_parse_fd_opt opt
= reg_parse_fd_opt(mem_ctx
, opts
);
844 DEBUG(0,("reg_parse_fd: NULL callback\n"));
848 nread
= read(fd
, buf_raw
, sizeof(buf_raw
));
850 DEBUG(0, ("reg_parse_fd: read failed: %s\n", strerror(errno
)));
858 if (!guess_charset(&iptr
, &ilen
,
859 &opt
.file_enc
, &opt
.str_enc
))
861 DEBUG(0, ("reg_parse_fd: failed to guess encoding\n"));
865 DEBUG(10, ("reg_parse_fd: encoding file: %s str: %s\n",
866 opt
.file_enc
, opt
.str_enc
));
869 if (!set_iconv(&cd
, "unix", opt
.file_enc
)) {
870 DEBUG(0, ("reg_parse_fd: failed to set file encoding %s\n",
875 parser
= reg_parse_new(mem_ctx
, *cb
, opt
.str_enc
, opt
.flags
);
879 olen
= sizeof(buf_unix
) - (optr
- buf_unix
) - 1 ;
881 memmove(buf_raw
, iptr
, ilen
);
883 nread
= read(fd
, buf_raw
+ ilen
, sizeof(buf_raw
) - ilen
);
885 DEBUG(0, ("reg_parse_fd: read failed: %s\n", strerror(errno
)));
894 smb_iconv(cd
, NULL
, NULL
, &optr
, &olen
);
899 nconv
= smb_iconv(cd
, &iptr
, &ilen
, &optr
, &olen
);
901 if (nconv
== (size_t)-1) {
902 handle_iconv_errno(errno
, buf_unix
, linenum
,
912 while ( srprs_line(&pos
, line
) && srprs_nl_no_eos(&pos
, line
, eof
)) {
914 ret
= reg_parse_line(parser
, cbuf_gets(line
, 0));
915 if (ret
< opt
.fail_level
) {
920 memmove(buf_unix
, pos
, optr
- pos
);
921 optr
-= (pos
- buf_unix
);
926 set_iconv(&cd
, NULL
, NULL
);
927 talloc_free(mem_ctx
);
931 int reg_parse_file(const char* fname
, const struct reg_parse_callback
* cb
,
937 fd
= open(fname
, O_RDONLY
);
939 DEBUG(0, ("reg_parse_file: open failed: %s\n", strerror(errno
)));
943 ret
= reg_parse_fd(fd
, cb
, opt
);
949 /* static struct registry_key *find_regkey_by_hnd(pipes_struct *p, */
950 /* struct policy_handle *hnd) */
952 /* struct registry_key *regkey = NULL; */
954 /* if(!find_policy_by_hnd(p,hnd,(void **)(void *)®key)) { */
955 /* DEBUG(2,("find_regkey_index_by_hnd: Registry Key not found: ")); */