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>
31 #include "reg_parse_internal.h"
32 #include "reg_parse.h"
33 #include "reg_format.h"
41 #include <sys/types.h>
46 enum reg_parse_state
{
54 struct reg_format_callback reg_format_callback
;
60 struct reg_parse_callback call
;
63 enum reg_parse_state state
;
64 struct reg_parse_options
* opt
;
65 smb_iconv_t str2UTF16
;
70 * @defgroup action Action
73 static bool act_key(struct reg_parse
* p
, cbuf
* keyname
, bool del
)
75 const char* name
= cbuf_gets(keyname
, 0);
76 cbuf_swap(p
->key
, keyname
);
78 assert(p
->state
== STATE_DEFAULT
|| p
->state
== STATE_KEY_OPEN
);
79 p
->state
= del
? STATE_DEFAULT
: STATE_KEY_OPEN
;
82 p
->ret
= p
->call
.key(p
->call
.data
, &name
, 1, del
);
86 static bool value_callback(struct reg_parse
* p
)
88 const char* name
= cbuf_gets(p
->valname
,0);
89 const uint8_t* val
= (const uint8_t*)cbuf_gets(p
->valblob
,0);
90 size_t len
= cbuf_getpos(p
->valblob
);
93 p
->ret
= p
->call
.val(p
->call
.data
, name
, p
->valtype
, val
, len
);
97 static bool act_val_hex(struct reg_parse
* p
, cbuf
* value
, bool cont
)
99 cbuf_swap(p
->valblob
, value
);
100 assert((p
->state
== STATE_KEY_OPEN
) || (p
->state
== STATE_VAL_HEX_CONT
));
103 p
->state
= STATE_VAL_HEX_CONT
;
105 p
->state
= STATE_KEY_OPEN
;
107 switch (p
->valtype
) {
110 if (p
->str2UTF16
!= NULL
) {
112 const char* src
= cbuf_gets(p
->valblob
, 0);
113 const size_t slen
= cbuf_getpos(p
->valblob
);
114 size_t dlen
= iconvert_talloc(p
,
119 cbuf_swapptr(p
->valblob
, &dst
, dlen
);
121 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
));
174 return value_callback(p
);
179 static bool act_val_del(struct reg_parse
* p
)
181 const char* name
= cbuf_gets(p
->valname
, 0);
183 assert(p
->call
.val_del
);
184 p
->ret
= p
->call
.val_del(p
->call
.data
, name
);
188 static bool act_comment (struct reg_parse
* p
, const char* txt
)
190 assert(p
->call
.comment
);
191 p
->ret
= p
->call
.comment(p
->call
.data
, txt
);
197 static int nop(void* data
)
203 struct reg_parse
* reg_parse_new(const void* ctx
,
204 struct reg_parse_callback cb
,
205 const char* str_enc
, unsigned flags
)
207 struct reg_parse
* s
= talloc_zero(ctx
, struct reg_parse
);
210 s
->key
= cbuf_new(s
);
211 s
->valname
= cbuf_new(s
);
212 s
->valblob
= cbuf_new(s
);
213 s
->tmp
= cbuf_new(s
);
214 if ( (s
->tmp
== NULL
) || (s
->valblob
== NULL
)
215 || (s
->valname
== NULL
) || (s
->key
== NULL
) )
220 s
->reg_format_callback
.writeline
= (reg_format_callback_writeline_t
)®_parse_line
;
221 s
->reg_format_callback
.data
= s
;
224 if (cb
.key
== NULL
) {
225 cb
.key
= (reg_parse_callback_key_t
)&nop
;
227 if (cb
.val
== NULL
) {
228 cb
.val
= (reg_parse_callback_val_t
)&nop
;
230 if (cb
.val_del
== NULL
) {
231 cb
.val_del
= (reg_parse_callback_val_del_t
)&nop
;
233 if (cb
.comment
== NULL
) {
234 cb
.comment
= (reg_parse_callback_comment_t
)&nop
;
239 s
->state
= STATE_DEFAULT
;
242 if (str_enc
&& !set_iconv(&s
->str2UTF16
, "UTF-16LE", str_enc
)) {
243 DEBUG(0, ("reg_parse_new: failed to set encoding: %s",
248 assert(&s
->reg_format_callback
== (struct reg_format_callback
*)s
);
256 * @defgroup parse Parser Primitive
262 static bool srprs_key(const char** ptr
, cbuf
* key
, bool* del
)
264 const char* pos
= *ptr
;
265 const char* closing_bracket_pos
= NULL
;
266 size_t closing_bracket_idx
= 0;
268 if (!srprs_skipws(&pos
) || !srprs_char(&pos
, '[')) {
272 *del
= srprs_char(&pos
, '-');
277 while (srprs_charsetinv(&pos
, "]\\", key
))
283 closing_bracket_idx
= cbuf_getpos(key
);
284 closing_bracket_pos
= pos
;
290 cbuf_putc(key
, '\\');
292 /* cbuf_puts(subkeyidx, cbuf_getpos(key), sizeof(size_t)) */
293 while (srprs_char(&pos
,'\\'))
298 if (closing_bracket_pos
== NULL
) {
302 /* remove trailing backslash (if any) */
303 if (*(closing_bracket_pos
-1)=='\\') {
304 closing_bracket_idx
--;
307 cbuf_setpos(key
, closing_bracket_idx
);
308 *ptr
= closing_bracket_pos
+1;
317 static bool srprs_val_name(const char** ptr
, cbuf
* name
)
319 const char* pos
= *ptr
;
320 const size_t spos
= cbuf_getpos(name
);
322 if ( !srprs_skipws(&pos
) ) {
326 if ( srprs_char(&pos
, '@') ) {
327 cbuf_puts(name
, "", -1);
329 else if (!srprs_quoted_string(&pos
, name
, NULL
)) {
333 if (!srprs_skipws(&pos
) || !srprs_char(&pos
, '=')) {
341 cbuf_setpos(name
, spos
);
345 static bool srprs_val_dword(const char** ptr
, uint32_t* type
, uint32_t* val
)
347 const char* pos
= *ptr
;
349 if (!srprs_str(&pos
, "dword:", -1)) {
353 if (!srprs_hex(&pos
, 8, val
)) {
362 static bool srprs_val_sz(const char** ptr
, uint32_t* type
, cbuf
* val
, bool* cont
)
364 if (!srprs_quoted_string(ptr
, val
, cont
)) {
373 static bool srprs_nl_no_eos(const char** ptr
, cbuf
* str
, bool eof
)
375 const char* pos
= *ptr
;
376 const size_t spos
= cbuf_getpos(str
);
378 if( srprs_nl(&pos
, str
) && (eof
|| *pos
!= '\0')) {
382 cbuf_setpos(str
, spos
);
387 static bool srprs_eol_cont(const char** ptr
, bool* cont
)
389 const char* pos
= *ptr
;
390 bool bs
= srprs_char(&pos
, '\\');
392 if (!srprs_eol(&pos
, NULL
)) {
401 /* matches the empty string, for zero length lists */
402 static bool srprs_val_hex_values(const char** ptr
, cbuf
* val
, bool* cont
)
404 const char* pos
= *ptr
;
408 if (!srprs_skipws(&pos
) || !srprs_hex(&pos
, 2, &u
) || !srprs_skipws(&pos
)) {
411 cbuf_putc(val
, (char)u
);
412 } while(srprs_char(&pos
, ','));
416 if (srprs_skipws(&pos
) && srprs_eol_cont(&pos
, cont
)) {
423 static bool srprs_val_hex(const char** ptr
, uint32_t* ptype
, cbuf
* val
,
426 const char* pos
= *ptr
;
429 if (!srprs_str(&pos
, "hex", -1)) {
433 if (srprs_char(&pos
, ':')) {
436 else if (!srprs_char(&pos
, '(') ||
437 !srprs_hex(&pos
, 8, &type
) ||
438 !srprs_char(&pos
,')') ||
439 !srprs_char(&pos
, ':'))
444 if (!srprs_val_hex_values(&pos
, val
, cont
)) {
454 static bool srprs_comment(const char** ptr
, cbuf
* str
)
456 return srprs_char(ptr
, ';') && srprs_line(ptr
, str
);
461 int reg_parse_set_options(struct reg_parse
* parser
, const char* options
)
463 static const char* DEFAULT
="enc=unix,flags=0";
467 void* ctx
= talloc_new(parser
);
469 if (options
== NULL
) {
473 while (srprs_option(&options
, ctx
, &key
, &val
)) {
474 if ((strcmp(key
, "enc") == 0) || (strcmp(key
, "strenc") == 0)) {
475 } else if ((strcmp(key
, "flags") == 0) && (val
!= NULL
)) {
478 parser
->flags
= strtol(val
, &end
, 0);
480 if ((end
==NULL
) || (*end
!= '\0')) {
481 DEBUG(0, ("Invalid flags format: %s\n",
482 val
? val
: "<NULL>"));
486 /* else if (strcmp(key, "hive") == 0) { */
487 /* if (strcmp(val, "short") == 0) { */
488 /* f->hive_fmt = REG_FMT_SHORT_HIVES; */
489 /* } else if (strcmp(val, "long") == 0) { */
490 /* f->hive_fmt = REG_FMT_LONG_HIVES; */
491 /* } else if (strcmp(val, "preserve") == 0) { */
492 /* f->hive_fmt = REG_FMT_PRESERVE_HIVES; */
494 /* DEBUG(0, ("Invalid hive format: %s\n", val)); */
504 int reg_parse_line(struct reg_parse
* parser
, const char* line
)
508 cbuf
* tmp
=cbuf_clear(parser
->tmp
);
519 switch (parser
->state
) {
520 case STATE_VAL_HEX_CONT
:
521 if (srprs_val_hex_values(&pos
, parser
->valblob
, &cont
)) {
522 cb_ok
= act_val_hex(parser
, parser
->valblob
, cont
);
525 case STATE_VAL_SZ_CONT
:
526 if (srprs_quoted_string(&pos
, parser
->valblob
, &cont
)) {
527 cb_ok
= act_val_sz(parser
, parser
->valblob
, cont
);
534 if ( !srprs_skipws(&pos
) ) {
539 if ( srprs_eol(&pos
, NULL
) ) {
544 else if (srprs_key(&pos
, tmp
, &del
)) {
545 cb_ok
= act_key(parser
, tmp
, del
);
549 else if (srprs_comment(&pos
, tmp
)) {
550 cb_ok
= act_comment(parser
, cbuf_gets(tmp
, 0));
554 else if ((parser
->linenum
== 1) && srprs_line(&pos
, tmp
) ) {
555 /* cb_ok = act_head(parser, cbuf_gets(tmp, 0)); */
559 else if (srprs_val_name(&pos
, tmp
)) {
561 cbuf_swap(parser
->valname
, tmp
);
564 if (parser
->state
!= STATE_KEY_OPEN
) {
565 DEBUG(0, ("value \"%s\" without a key at line: %i",
566 cbuf_gets(parser
->valname
, 0), parser
->linenum
));
570 if (!srprs_skipws(&pos
)) {
574 if (srprs_char(&pos
, '-')) {
575 cb_ok
= act_val_del(parser
);
577 else if (srprs_val_dword(&pos
, &parser
->valtype
, &dw
)) {
578 cb_ok
= act_val_dw(parser
, dw
);
580 else if (srprs_val_sz(&pos
, &parser
->valtype
, tmp
, &cont
)) {
581 cb_ok
= act_val_sz(parser
, tmp
, cont
);
583 else if (srprs_val_hex(&pos
, &parser
->valtype
, tmp
, &cont
)){
584 cb_ok
= act_val_hex(parser
, tmp
, cont
);
587 DEBUG(0, ("value \"%s\" parse error"
588 "at line: %i pos: %li : %s",
589 cbuf_gets(parser
->valname
, 0), parser
->linenum
,
590 (long int)(pos
-line
), pos
));
595 DEBUG(0, ("unrecognized line %i : %s\n", parser
->linenum
, line
));
603 if (!srprs_skipws(&pos
) || !srprs_eol(&pos
, NULL
)) {
604 DEBUG(0, ("trailing garbage at line: %i pos: %li : %s\n",
605 parser
->linenum
, (long int)(pos
-line
), pos
));
611 /******************************************************************************/
616 static bool lookslike_utf16(const char* line
, size_t len
, bool* little_endian
)
618 static const uint16_t M_LE
= 0xFF80;
619 static const uint16_t M_BE
= 0x80FF;
623 size_t l
= MIN(len
/2, 64);
624 uint16_t* u
= (uint16_t*)line
;
632 } else if ( u
[0] & M_BE
) {
639 for (i
=1; i
<l
; i
++) {
649 static bool lookslike_dos(const char* line
, size_t len
)
652 for (i
=0; i
<len
; i
++) {
653 if ( (line
[i
] == '\0') || (line
[i
] & 0x80) ) {
656 if ( (line
[i
] == '\r') && (i
+1 < len
) && (line
[i
+1] == '\n') ) {
663 static bool guess_charset(const char** ptr
,
665 const char** file_enc
,
666 const char** str_enc
)
668 const char* charset
= NULL
;
669 const char* pos
= *ptr
;
675 if (srprs_bom(&pos
, &charset
, NULL
)) {
676 *len
-= (pos
- *ptr
);
678 if (*file_enc
== NULL
) {
681 else if( strcmp(*file_enc
, charset
) != 0 ) {
682 DEBUG(0, ("file encoding forced to %s\n",
686 else if (*file_enc
== NULL
) {
688 if (lookslike_utf16(*ptr
, *len
, &le
)) {
689 *file_enc
= le
? "UTF-16LE" : "UTF-16BE";
691 else if (lookslike_dos(*ptr
, *len
)) {
699 if ((str_enc
!= NULL
) && (*str_enc
== NULL
)) {
700 *str_enc
= ( strncmp(*ptr
, "REGEDIT4", 8) == 0)
709 struct reg_parse_fd_opt
{
710 const char* file_enc
;
716 static struct reg_parse_fd_opt
717 reg_parse_fd_opt(void* mem_ctx
, const char* options
)
719 struct reg_parse_fd_opt ret
= {
725 void* ctx
= talloc_new(mem_ctx
);
728 if (options
== NULL
) {
732 while (srprs_option(&options
, ctx
, &key
, &val
)) {
733 if (strcmp(key
, "enc") == 0) {
734 ret
.file_enc
= talloc_steal(mem_ctx
, val
);
735 ret
.str_enc
= ret
.file_enc
;
736 } else if (strcmp(key
, "strenc") == 0) {
737 ret
.str_enc
= talloc_steal(mem_ctx
, val
);
738 } else if (strcmp(key
, "fileenc") == 0) {
739 ret
.file_enc
= talloc_steal(mem_ctx
, val
);
740 } else if ((strcmp(key
, "flags") == 0) && (val
!= NULL
)) {
743 ret
.flags
= strtol(val
, &end
, 0);
745 if ((end
==NULL
) || (*end
!= '\0')) {
746 DEBUG(0, ("Invalid format \"%s\": %s\n",
747 key
, val
? val
: "<NULL>"));
749 } else if ((strcmp(key
, "fail") == 0) && (val
!= NULL
)) {
752 ret
.fail_level
= -strtol(val
, &end
, 0);
754 if ((end
==NULL
) || (*end
!= '\0')) {
755 DEBUG(0, ("Invalid format \"%s\": %s\n",
756 key
, val
? val
: "<NULL>"));
767 handle_iconv_errno(int err
, const char* obuf
, size_t linenum
,
768 smb_iconv_t cd
, const char** iptr
, size_t* ilen
,
769 char** optr
, size_t *olen
)
771 const char *pos
= obuf
;
772 const char *ptr
= obuf
;
775 /* DEBUG(0, ("Incomplete multibyte sequence\n")); */
785 while (srprs_line(&ptr
, NULL
) && srprs_nl(&ptr
, NULL
)) {
790 pos
= MAX(obuf
, *optr
-60);
792 DEBUG(0, ("Illegal multibyte sequence at line %lu: %s",
793 (long unsigned)(linenum
+1), pos
));
798 DEBUGADD(0, ("<%02x>", (unsigned char)**iptr
));
803 /* Todo: parametrize, e.g. skip: *optr++ = *iptr++; */
807 if (smb_iconv(cd
, iptr
, &il
, optr
, olen
) != (size_t)-1 || (errno
!= EILSEQ
)) {
814 while ((*ilen
> 0) && (*olen
> 0));
820 int reg_parse_fd(int fd
, const struct reg_parse_callback
* cb
, const char* opts
)
822 void* mem_ctx
= talloc_stackframe();
823 cbuf
* line
= cbuf_new(mem_ctx
);
824 smb_iconv_t cd
= (smb_iconv_t
)-1;
825 struct reg_parse
* parser
= NULL
;
840 struct reg_parse_fd_opt opt
= reg_parse_fd_opt(mem_ctx
, opts
);
843 DEBUG(0,("reg_parse_fd: NULL callback\n"));
847 nread
= read(fd
, buf_raw
, sizeof(buf_raw
));
849 DEBUG(0, ("reg_parse_fd: read failed: %s\n", strerror(errno
)));
857 if (!guess_charset(&iptr
, &ilen
,
858 &opt
.file_enc
, &opt
.str_enc
))
860 DEBUG(0, ("reg_parse_fd: failed to guess encoding\n"));
864 DEBUG(0, ("reg_parse_fd: encoding file: %s str: %s\n",
865 opt
.file_enc
, opt
.str_enc
));
868 if (!set_iconv(&cd
, "unix", opt
.file_enc
)) {
869 DEBUG(0, ("reg_parse_fd: failed to set file encoding %s\n",
874 parser
= reg_parse_new(mem_ctx
, *cb
, opt
.str_enc
, opt
.flags
);
878 olen
= sizeof(buf_unix
) - (optr
- buf_unix
) - 1 ;
880 memmove(buf_raw
, iptr
, ilen
);
882 nread
= read(fd
, buf_raw
+ ilen
, sizeof(buf_raw
) - ilen
);
884 DEBUG(0, ("reg_parse_fd: read failed: %s\n", strerror(errno
)));
893 smb_iconv(cd
, NULL
, NULL
, &optr
, &olen
);
898 nconv
= smb_iconv(cd
, &iptr
, &ilen
, &optr
, &olen
);
900 if (nconv
== (size_t)-1) {
901 handle_iconv_errno(errno
, buf_unix
, linenum
,
911 while ( srprs_line(&pos
, line
) && srprs_nl_no_eos(&pos
, line
, eof
)) {
913 ret
= reg_parse_line(parser
, cbuf_gets(line
, 0));
914 if (ret
< opt
.fail_level
) {
919 memmove(buf_unix
, pos
, optr
- pos
);
920 optr
-= (pos
- buf_unix
);
925 set_iconv(&cd
, NULL
, NULL
);
926 talloc_free(mem_ctx
);
930 int reg_parse_file(const char* fname
, const struct reg_parse_callback
* cb
,
936 fd
= open(fname
, O_RDONLY
);
938 DEBUG(0, ("reg_parse_file: open failed: %s\n", strerror(errno
)));
942 ret
= reg_parse_fd(fd
, cb
, opt
);
948 /* static struct registry_key *find_regkey_by_hnd(pipes_struct *p, */
949 /* struct policy_handle *hnd) */
951 /* struct registry_key *regkey = NULL; */
953 /* if(!find_policy_by_hnd(p,hnd,(void **)(void *)®key)) { */
954 /* DEBUG(2,("find_regkey_index_by_hnd: Registry Key not found: ")); */