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"
45 enum reg_parse_state
{
53 struct reg_format_callback reg_format_callback
;
59 struct reg_parse_callback call
;
62 enum reg_parse_state state
;
63 struct reg_parse_options
* opt
;
64 smb_iconv_t str2UTF16
;
69 * @defgroup action Action
72 static bool act_key(struct reg_parse
* p
, cbuf
* keyname
, bool del
)
74 const char* name
= cbuf_gets(keyname
, 0);
75 cbuf_swap(p
->key
, keyname
);
77 assert(p
->state
== STATE_DEFAULT
|| p
->state
== STATE_KEY_OPEN
);
78 p
->state
= del
? STATE_DEFAULT
: STATE_KEY_OPEN
;
81 p
->ret
= p
->call
.key(p
->call
.data
, &name
, 1, del
);
85 static bool value_callback(struct reg_parse
* p
)
87 const char* name
= cbuf_gets(p
->valname
,0);
88 const uint8_t* val
= (const uint8_t*)cbuf_gets(p
->valblob
,0);
89 size_t len
= cbuf_getpos(p
->valblob
);
92 p
->ret
= p
->call
.val(p
->call
.data
, name
, p
->valtype
, val
, len
);
96 static bool act_val_hex(struct reg_parse
* p
, cbuf
* value
, bool cont
)
98 cbuf_swap(p
->valblob
, value
);
99 assert((p
->state
== STATE_KEY_OPEN
) || (p
->state
== STATE_VAL_HEX_CONT
));
102 p
->state
= STATE_VAL_HEX_CONT
;
104 p
->state
= STATE_KEY_OPEN
;
106 switch (p
->valtype
) {
109 if (p
->str2UTF16
!= NULL
) {
111 const char* src
= cbuf_gets(p
->valblob
, 0);
112 const size_t slen
= cbuf_getpos(p
->valblob
);
113 size_t dlen
= iconvert_talloc(p
,
118 cbuf_swapptr(p
->valblob
, &dst
, dlen
);
120 DEBUG(0, ("iconvert_talloc failed\n"));
127 return value_callback(p
);
132 static bool act_val_dw(struct reg_parse
* p
, uint32_t val
)
134 assert(p
->valtype
== REG_DWORD
);
135 assert(p
->state
== STATE_KEY_OPEN
);
137 cbuf_clear(p
->valblob
);
139 if (cbuf_putdw(p
->valblob
, val
) < 0) {
142 return value_callback(p
);
145 static bool act_val_sz(struct reg_parse
* p
, cbuf
* value
, bool cont
)
147 cbuf_swap(p
->valblob
, value
);
149 assert(p
->valtype
== REG_SZ
);
150 assert((p
->state
== STATE_KEY_OPEN
) || (p
->state
== STATE_VAL_SZ_CONT
));
153 p
->state
= STATE_VAL_SZ_CONT
;
157 const char* src
= cbuf_gets(p
->valblob
, 0);
159 p
->state
= STATE_KEY_OPEN
;
162 if (convert_string_talloc(p
->valblob
, CH_UNIX
, CH_UTF16LE
,
166 cbuf_swapptr(p
->valblob
, &dst
, dlen
);
168 DEBUG(0, ("convert_string_talloc failed: >%s<\n"
169 "use it as is\t", src
));
173 return value_callback(p
);
178 static bool act_val_del(struct reg_parse
* p
)
180 const char* name
= cbuf_gets(p
->valname
, 0);
182 assert(p
->call
.val_del
);
183 p
->ret
= p
->call
.val_del(p
->call
.data
, name
);
187 static bool act_comment (struct reg_parse
* p
, const char* txt
)
189 assert(p
->call
.comment
);
190 p
->ret
= p
->call
.comment(p
->call
.data
, txt
);
196 static int nop(void* data
)
202 struct reg_parse
* reg_parse_new(const void* ctx
,
203 struct reg_parse_callback cb
,
204 const char* str_enc
, unsigned flags
)
206 struct reg_parse
* s
= talloc_zero(ctx
, struct reg_parse
);
209 s
->key
= cbuf_new(s
);
210 s
->valname
= cbuf_new(s
);
211 s
->valblob
= cbuf_new(s
);
212 s
->tmp
= cbuf_new(s
);
213 if ( (s
->tmp
== NULL
) || (s
->valblob
== NULL
)
214 || (s
->valname
== NULL
) || (s
->key
== NULL
) )
219 s
->reg_format_callback
.writeline
= (reg_format_callback_writeline_t
)®_parse_line
;
220 s
->reg_format_callback
.data
= s
;
223 if (cb
.key
== NULL
) {
224 cb
.key
= (reg_parse_callback_key_t
)&nop
;
226 if (cb
.val
== NULL
) {
227 cb
.val
= (reg_parse_callback_val_t
)&nop
;
229 if (cb
.val_del
== NULL
) {
230 cb
.val_del
= (reg_parse_callback_val_del_t
)&nop
;
232 if (cb
.comment
== NULL
) {
233 cb
.comment
= (reg_parse_callback_comment_t
)&nop
;
238 s
->state
= STATE_DEFAULT
;
241 if (str_enc
&& !set_iconv(&s
->str2UTF16
, "UTF-16LE", str_enc
)) {
242 DEBUG(0, ("reg_parse_new: failed to set encoding: %s",
247 assert(&s
->reg_format_callback
== (struct reg_format_callback
*)s
);
255 * @defgroup parse Parser Primitive
261 static bool srprs_key(const char** ptr
, cbuf
* key
, bool* del
)
263 const char* pos
= *ptr
;
264 const char* closing_bracket_pos
= NULL
;
265 size_t closing_bracket_idx
= 0;
267 if (!srprs_skipws(&pos
) || !srprs_char(&pos
, '[')) {
271 *del
= srprs_char(&pos
, '-');
276 while (srprs_charsetinv(&pos
, "]\\", key
))
282 closing_bracket_idx
= cbuf_getpos(key
);
283 closing_bracket_pos
= pos
;
289 cbuf_putc(key
, '\\');
291 /* cbuf_puts(subkeyidx, cbuf_getpos(key), sizeof(size_t)) */
292 while (srprs_char(&pos
,'\\'))
297 if (closing_bracket_pos
== NULL
) {
301 /* remove trailing backslash (if any) */
302 if (*(closing_bracket_pos
-1)=='\\') {
303 closing_bracket_idx
--;
306 cbuf_setpos(key
, closing_bracket_idx
);
307 *ptr
= closing_bracket_pos
+1;
316 static bool srprs_val_name(const char** ptr
, cbuf
* name
)
318 const char* pos
= *ptr
;
319 const size_t spos
= cbuf_getpos(name
);
321 if ( !srprs_skipws(&pos
) ) {
325 if ( srprs_char(&pos
, '@') ) {
326 cbuf_puts(name
, "", -1);
328 else if (!srprs_quoted_string(&pos
, name
, NULL
)) {
332 if (!srprs_skipws(&pos
) || !srprs_char(&pos
, '=')) {
340 cbuf_setpos(name
, spos
);
344 static bool srprs_val_dword(const char** ptr
, uint32_t* type
, uint32_t* val
)
346 const char* pos
= *ptr
;
348 if (!srprs_str(&pos
, "dword:", -1)) {
352 if (!srprs_hex(&pos
, 8, val
)) {
361 static bool srprs_val_sz(const char** ptr
, uint32_t* type
, cbuf
* val
, bool* cont
)
363 if (!srprs_quoted_string(ptr
, val
, cont
)) {
372 static bool srprs_nl_no_eos(const char** ptr
, cbuf
* str
, bool eof
)
374 const char* pos
= *ptr
;
375 const size_t spos
= cbuf_getpos(str
);
377 if( srprs_nl(&pos
, str
) && (eof
|| *pos
!= '\0')) {
381 cbuf_setpos(str
, spos
);
386 static bool srprs_eol_cont(const char** ptr
, bool* cont
)
388 const char* pos
= *ptr
;
389 bool bs
= srprs_char(&pos
, '\\');
391 if (!srprs_eol(&pos
, NULL
)) {
400 /* matches the empty string, for zero length lists */
401 static bool srprs_val_hex_values(const char** ptr
, cbuf
* val
, bool* cont
)
403 const char* pos
= *ptr
;
407 if (!srprs_skipws(&pos
) || !srprs_hex(&pos
, 2, &u
) || !srprs_skipws(&pos
)) {
410 cbuf_putc(val
, (char)u
);
411 } while(srprs_char(&pos
, ','));
415 if (srprs_skipws(&pos
) && srprs_eol_cont(&pos
, cont
)) {
422 static bool srprs_val_hex(const char** ptr
, uint32_t* ptype
, cbuf
* val
,
425 const char* pos
= *ptr
;
428 if (!srprs_str(&pos
, "hex", -1)) {
432 if (srprs_char(&pos
, ':')) {
435 else if (!srprs_char(&pos
, '(') ||
436 !srprs_hex(&pos
, 8, &type
) ||
437 !srprs_char(&pos
,')') ||
438 !srprs_char(&pos
, ':'))
443 if (!srprs_val_hex_values(&pos
, val
, cont
)) {
453 static bool srprs_comment(const char** ptr
, cbuf
* str
)
455 return srprs_char(ptr
, ';') && srprs_line(ptr
, str
);
460 int reg_parse_set_options(struct reg_parse
* parser
, const char* options
)
462 static const char* DEFAULT
="enc=unix,flags=0";
466 void* ctx
= talloc_new(parser
);
468 if (options
== NULL
) {
472 while (srprs_option(&options
, ctx
, &key
, &val
)) {
473 if ((strcmp(key
, "enc") == 0) || (strcmp(key
, "strenc") == 0)) {
474 } else if ((strcmp(key
, "flags") == 0) && (val
!= NULL
)) {
477 parser
->flags
= strtol(val
, &end
, 0);
479 if ((end
==NULL
) || (*end
!= '\0')) {
480 DEBUG(0, ("Invalid flags format: %s\n",
481 val
? val
: "<NULL>"));
485 /* else if (strcmp(key, "hive") == 0) { */
486 /* if (strcmp(val, "short") == 0) { */
487 /* f->hive_fmt = REG_FMT_SHORT_HIVES; */
488 /* } else if (strcmp(val, "long") == 0) { */
489 /* f->hive_fmt = REG_FMT_LONG_HIVES; */
490 /* } else if (strcmp(val, "preserve") == 0) { */
491 /* f->hive_fmt = REG_FMT_PRESERVE_HIVES; */
493 /* DEBUG(0, ("Invalid hive format: %s\n", val)); */
503 int reg_parse_line(struct reg_parse
* parser
, const char* line
)
507 cbuf
* tmp
=cbuf_clear(parser
->tmp
);
518 switch (parser
->state
) {
519 case STATE_VAL_HEX_CONT
:
520 if (srprs_val_hex_values(&pos
, parser
->valblob
, &cont
)) {
521 cb_ok
= act_val_hex(parser
, parser
->valblob
, cont
);
524 case STATE_VAL_SZ_CONT
:
525 if (srprs_quoted_string(&pos
, parser
->valblob
, &cont
)) {
526 cb_ok
= act_val_sz(parser
, parser
->valblob
, cont
);
533 if ( !srprs_skipws(&pos
) ) {
538 if ( srprs_eol(&pos
, NULL
) ) {
543 else if (srprs_key(&pos
, tmp
, &del
)) {
544 cb_ok
= act_key(parser
, tmp
, del
);
548 else if (srprs_comment(&pos
, tmp
)) {
549 cb_ok
= act_comment(parser
, cbuf_gets(tmp
, 0));
553 else if ((parser
->linenum
== 1) && srprs_line(&pos
, tmp
) ) {
554 /* cb_ok = act_head(parser, cbuf_gets(tmp, 0)); */
558 else if (srprs_val_name(&pos
, tmp
)) {
560 cbuf_swap(parser
->valname
, tmp
);
563 if (parser
->state
!= STATE_KEY_OPEN
) {
564 DEBUG(0, ("value \"%s\" without a key at line: %i",
565 cbuf_gets(parser
->valname
, 0), parser
->linenum
));
569 if (!srprs_skipws(&pos
)) {
573 if (srprs_char(&pos
, '-')) {
574 cb_ok
= act_val_del(parser
);
576 else if (srprs_val_dword(&pos
, &parser
->valtype
, &dw
)) {
577 cb_ok
= act_val_dw(parser
, dw
);
579 else if (srprs_val_sz(&pos
, &parser
->valtype
, tmp
, &cont
)) {
580 cb_ok
= act_val_sz(parser
, tmp
, cont
);
582 else if (srprs_val_hex(&pos
, &parser
->valtype
, tmp
, &cont
)){
583 cb_ok
= act_val_hex(parser
, tmp
, cont
);
586 DEBUG(0, ("value \"%s\" parse error"
587 "at line: %i pos: %li : %s",
588 cbuf_gets(parser
->valname
, 0), parser
->linenum
,
589 (long int)(pos
-line
), pos
));
594 DEBUG(0, ("unrecognized line %i : %s\n", parser
->linenum
, line
));
602 if (!srprs_skipws(&pos
) || !srprs_eol(&pos
, NULL
)) {
603 DEBUG(0, ("trailing garbage at line: %i pos: %li : %s\n",
604 parser
->linenum
, (long int)(pos
-line
), pos
));
610 /******************************************************************************/
615 static bool lookslike_utf16(const char* line
, size_t len
, bool* little_endian
)
617 static const uint16_t M_LE
= 0xFF80;
618 static const uint16_t M_BE
= 0x80FF;
622 size_t l
= MIN(len
/2, 64);
623 const uint16_t* u
= (const uint16_t*)line
;
631 } else if ( u
[0] & M_BE
) {
638 for (i
=1; i
<l
; i
++) {
648 static bool lookslike_dos(const char* line
, size_t len
)
651 for (i
=0; i
<len
; i
++) {
652 if ( (line
[i
] == '\0') || (line
[i
] & 0x80) ) {
655 if ( (line
[i
] == '\r') && (i
+1 < len
) && (line
[i
+1] == '\n') ) {
662 static bool guess_charset(const char** ptr
,
664 const char** file_enc
,
665 const char** str_enc
)
667 const char* charset
= NULL
;
668 const char* pos
= *ptr
;
674 if (srprs_bom(&pos
, &charset
, NULL
)) {
675 *len
-= (pos
- *ptr
);
677 if (*file_enc
== NULL
) {
680 else if( strcmp(*file_enc
, charset
) != 0 ) {
681 DEBUG(0, ("file encoding forced to %s\n",
685 else if (*file_enc
== NULL
) {
687 if (lookslike_utf16(*ptr
, *len
, &le
)) {
688 *file_enc
= le
? "UTF-16LE" : "UTF-16BE";
690 else if (lookslike_dos(*ptr
, *len
)) {
698 if ((str_enc
!= NULL
) && (*str_enc
== NULL
)) {
699 *str_enc
= ( strncmp(*ptr
, "REGEDIT4", 8) == 0)
708 struct reg_parse_fd_opt
{
709 const char* file_enc
;
715 static struct reg_parse_fd_opt
716 reg_parse_fd_opt(void* mem_ctx
, const char* options
)
718 struct reg_parse_fd_opt ret
= {
724 void* ctx
= talloc_new(mem_ctx
);
727 if (options
== NULL
) {
731 while (srprs_option(&options
, ctx
, &key
, &val
)) {
732 if (strcmp(key
, "enc") == 0) {
733 ret
.file_enc
= talloc_steal(mem_ctx
, val
);
734 ret
.str_enc
= ret
.file_enc
;
735 } else if (strcmp(key
, "strenc") == 0) {
736 ret
.str_enc
= talloc_steal(mem_ctx
, val
);
737 } else if (strcmp(key
, "fileenc") == 0) {
738 ret
.file_enc
= talloc_steal(mem_ctx
, val
);
739 } else if ((strcmp(key
, "flags") == 0) && (val
!= NULL
)) {
742 ret
.flags
= strtol(val
, &end
, 0);
744 if ((end
==NULL
) || (*end
!= '\0')) {
745 DEBUG(0, ("Invalid format \"%s\": %s\n",
746 key
, val
? val
: "<NULL>"));
748 } else if ((strcmp(key
, "fail") == 0) && (val
!= NULL
)) {
751 ret
.fail_level
= -strtol(val
, &end
, 0);
753 if ((end
==NULL
) || (*end
!= '\0')) {
754 DEBUG(0, ("Invalid format \"%s\": %s\n",
755 key
, val
? val
: "<NULL>"));
766 handle_iconv_errno(int err
, const char* obuf
, size_t linenum
,
767 smb_iconv_t cd
, const char** iptr
, size_t* ilen
,
768 char** optr
, size_t *olen
)
770 const char *pos
= obuf
;
771 const char *ptr
= obuf
;
774 /* DEBUG(0, ("Incomplete multibyte sequence\n")); */
784 while (srprs_line(&ptr
, NULL
) && srprs_nl(&ptr
, NULL
)) {
789 pos
= MAX(obuf
, *optr
-60);
791 DEBUG(0, ("Illegal multibyte sequence at line %lu: %s",
792 (long unsigned)(linenum
+1), pos
));
797 DEBUGADD(0, ("<%02x>", (unsigned char)**iptr
));
802 /* Todo: parametrize, e.g. skip: *optr++ = *iptr++; */
806 if (smb_iconv(cd
, iptr
, &il
, optr
, olen
) != (size_t)-1 || (errno
!= EILSEQ
)) {
813 while ((*ilen
> 0) && (*olen
> 0));
819 int reg_parse_fd(int fd
, const struct reg_parse_callback
* cb
, const char* opts
)
821 void* mem_ctx
= talloc_stackframe();
822 cbuf
* line
= cbuf_new(mem_ctx
);
823 smb_iconv_t cd
= (smb_iconv_t
)-1;
824 struct reg_parse
* parser
= NULL
;
839 struct reg_parse_fd_opt opt
= reg_parse_fd_opt(mem_ctx
, opts
);
842 DEBUG(0,("reg_parse_fd: NULL callback\n"));
846 nread
= read(fd
, buf_raw
, sizeof(buf_raw
));
848 DEBUG(0, ("reg_parse_fd: read failed: %s\n", strerror(errno
)));
856 if (!guess_charset(&iptr
, &ilen
,
857 &opt
.file_enc
, &opt
.str_enc
))
859 DEBUG(0, ("reg_parse_fd: failed to guess encoding\n"));
863 DEBUG(10, ("reg_parse_fd: encoding file: %s str: %s\n",
864 opt
.file_enc
, opt
.str_enc
));
867 if (!set_iconv(&cd
, "unix", opt
.file_enc
)) {
868 DEBUG(0, ("reg_parse_fd: failed to set file encoding %s\n",
873 parser
= reg_parse_new(mem_ctx
, *cb
, opt
.str_enc
, opt
.flags
);
877 olen
= sizeof(buf_unix
) - (optr
- buf_unix
) - 1 ;
879 memmove(buf_raw
, iptr
, ilen
);
881 nread
= read(fd
, buf_raw
+ ilen
, sizeof(buf_raw
) - ilen
);
883 DEBUG(0, ("reg_parse_fd: read failed: %s\n", strerror(errno
)));
892 smb_iconv(cd
, NULL
, NULL
, &optr
, &olen
);
897 nconv
= smb_iconv(cd
, &iptr
, &ilen
, &optr
, &olen
);
899 if (nconv
== (size_t)-1) {
900 handle_iconv_errno(errno
, buf_unix
, linenum
,
910 while ( srprs_line(&pos
, line
) && srprs_nl_no_eos(&pos
, line
, eof
)) {
912 ret
= reg_parse_line(parser
, cbuf_gets(line
, 0));
913 if (ret
< opt
.fail_level
) {
918 memmove(buf_unix
, pos
, optr
- pos
);
919 optr
-= (pos
- buf_unix
);
924 set_iconv(&cd
, NULL
, NULL
);
925 talloc_free(mem_ctx
);
929 int reg_parse_file(const char* fname
, const struct reg_parse_callback
* cb
,
935 fd
= open(fname
, O_RDONLY
);
937 DEBUG(0, ("reg_parse_file: open failed: %s\n", strerror(errno
)));
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: ")); */