s3-rpc_server: run minimal_includes.pl.
[samba.git] / source3 / registry / reg_parse.c
1 /*
2  * Samba Unix/Linux SMB client library
3  *
4  * Copyright (C) Gregor Beck 2010
5  *
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.
10  *
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.
15  *
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/>.
18  */
19
20 /**
21  * @brief  Parser for dot.reg files
22  * @file   reg_parse.c
23  * @author Gregor Beck <gb@sernet.de>
24  * @date   Jun 2010
25  *
26  */
27
28 #include "includes.h"
29 #include "system/filesys.h"
30 #include "cbuf.h"
31 #include "srprs.h"
32 #include "reg_parse_internal.h"
33 #include "reg_parse.h"
34 #include "reg_format.h"
35
36 #include <stdio.h>
37 #include <unistd.h>
38 #include <wchar.h>
39 #include <talloc.h>
40 #include <stdbool.h>
41 #include <string.h>
42 #include <sys/types.h>
43 #include <regex.h>
44 #include <assert.h>
45 #include <stdint.h>
46
47 enum reg_parse_state {
48         STATE_DEFAULT,
49         STATE_KEY_OPEN,
50         STATE_VAL_HEX_CONT,
51         STATE_VAL_SZ_CONT
52 };
53
54 struct reg_parse {
55         struct reg_format_callback reg_format_callback;
56         cbuf* key;
57         cbuf* valname;
58         uint32_t   valtype;
59         cbuf* valblob;
60         cbuf* tmp;
61         struct reg_parse_callback call;
62         int ret;
63         int linenum;
64         enum reg_parse_state state;
65         struct reg_parse_options* opt;
66         smb_iconv_t str2UTF16;
67         unsigned flags;
68 };
69
70 /**
71  * @defgroup action Action
72  * @{
73  */
74 static bool act_key(struct reg_parse* p, cbuf* keyname, bool del)
75 {
76         const char* name = cbuf_gets(keyname, 0);
77         cbuf_swap(p->key, keyname);
78
79         assert(p->state == STATE_DEFAULT || p->state == STATE_KEY_OPEN);
80         p->state = del ? STATE_DEFAULT : STATE_KEY_OPEN;
81
82         assert(p->call.key);
83         p->ret = p->call.key(p->call.data, &name, 1, del);
84         return p->ret >= 0;
85 }
86
87 static bool value_callback(struct reg_parse* p)
88 {
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);
92
93         assert(p->call.val);
94         p->ret = p->call.val(p->call.data, name, p->valtype, val, len);
95         return p->ret >= 0;
96 }
97
98 static bool act_val_hex(struct reg_parse* p, cbuf* value, bool cont)
99 {
100         cbuf_swap(p->valblob, value);
101         assert((p->state == STATE_KEY_OPEN) || (p->state == STATE_VAL_HEX_CONT));
102
103         if (cont) {
104                 p->state = STATE_VAL_HEX_CONT;
105         } else {
106                 p->state = STATE_KEY_OPEN;
107
108                 switch (p->valtype) {
109                 case REG_EXPAND_SZ:
110                 case REG_MULTI_SZ:
111                         if (p->str2UTF16 != NULL) {
112                                 char* dst = 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,
116                                                               p->str2UTF16,
117                                                               src, slen,
118                                                               &dst);
119                                 if (dlen != -1) {
120                                         cbuf_swapptr(p->valblob, &dst, dlen);
121                                 } else {
122                                         DEBUG(0, ("iconvert_talloc failed\n"));
123                                 }
124                                 talloc_free(dst);
125                         }
126                 default:
127                         break;
128                 }
129                 return value_callback(p);
130         }
131         return true;
132 }
133
134 static bool act_val_dw(struct reg_parse* p, uint32_t val)
135 {
136         assert(p->valtype == REG_DWORD);
137         assert(p->state == STATE_KEY_OPEN);
138
139         cbuf_clear(p->valblob);
140
141         if (cbuf_putdw(p->valblob, val) < 0) {
142                 return false;
143         }
144         return value_callback(p);
145 }
146
147 static bool act_val_sz(struct reg_parse* p, cbuf* value, bool cont)
148 {
149         cbuf_swap(p->valblob, value);
150
151         assert(p->valtype == REG_SZ);
152         assert((p->state == STATE_KEY_OPEN) || (p->state == STATE_VAL_SZ_CONT));
153
154         if (cont) {
155                 p->state = STATE_VAL_SZ_CONT;
156         } else {
157                 char* dst = NULL;
158                 size_t dlen;
159                 const char* src = cbuf_gets(p->valblob, 0);
160
161                 p->state = STATE_KEY_OPEN;
162
163
164                 if (convert_string_talloc(p->valblob, CH_UNIX, CH_UTF16LE,
165                                           src, strlen(src)+1,
166                                           &dst, &dlen))
167                 {
168                         cbuf_swapptr(p->valblob, &dst, dlen);
169                 } else {
170                         DEBUG(0, ("convert_string_talloc failed: >%s<\n"
171                                   "use it as is\t", src));
172                 }
173                 talloc_free(dst);
174
175                 return value_callback(p);
176         }
177         return true;
178 }
179
180 static bool act_val_del(struct reg_parse* p)
181 {
182         const char* name = cbuf_gets(p->valname, 0);
183
184         assert(p->call.val_del);
185         p->ret = p->call.val_del(p->call.data, name);
186         return p->ret >= 0;
187 }
188
189 static bool act_comment (struct reg_parse* p, const char* txt)
190 {
191         assert(p->call.comment);
192         p->ret = p->call.comment(p->call.data, txt);
193         return p->ret >= 0;
194 }
195 /**@}*/
196
197
198 static int nop(void* data)
199 {
200         return 0;
201 }
202
203
204 struct reg_parse* reg_parse_new(const void* ctx,
205                                 struct reg_parse_callback cb,
206                                 const char* str_enc, unsigned flags)
207 {
208         struct reg_parse* s = talloc_zero(ctx, struct reg_parse);
209         if (s == NULL)
210                 return NULL;
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) )
217         {
218                 goto fail;
219         }
220
221         s->reg_format_callback.writeline = (reg_format_callback_writeline_t)&reg_parse_line;
222         s->reg_format_callback.data      = s;
223
224         s->valtype = 0;
225         if (cb.key == NULL) {
226                 cb.key = (reg_parse_callback_key_t)&nop;
227         }
228         if (cb.val == NULL) {
229                 cb.val = (reg_parse_callback_val_t)&nop;
230         }
231         if (cb.val_del == NULL) {
232                 cb.val_del = (reg_parse_callback_val_del_t)&nop;
233         }
234         if (cb.comment == NULL) {
235                 cb.comment = (reg_parse_callback_comment_t)&nop;
236         }
237
238         s->call = cb;
239         s->linenum = 0;
240         s->state = STATE_DEFAULT;
241         s->flags = flags;
242
243         if (str_enc && !set_iconv(&s->str2UTF16, "UTF-16LE", str_enc)) {
244                 DEBUG(0, ("reg_parse_new: failed to set encoding: %s",
245                           str_enc));
246                 goto fail;
247         }
248
249         assert(&s->reg_format_callback == (struct reg_format_callback*)s);
250         return s;
251 fail:
252         talloc_free(s);
253         return NULL;
254 }
255
256 /**
257  * @defgroup parse Parser Primitive
258  * @ingroup internal
259  * @{
260  */
261
262
263 static bool srprs_key(const char** ptr, cbuf* key, bool* del)
264 {
265         const char* pos = *ptr;
266         const char* closing_bracket_pos = NULL;
267         size_t      closing_bracket_idx = 0;
268
269         if (!srprs_skipws(&pos) || !srprs_char(&pos, '[')) {
270                 return false;
271         }
272
273         *del = srprs_char(&pos, '-');
274
275         cbuf_clear(key);
276
277         while (true) {
278                 while (srprs_charsetinv(&pos, "]\\", key))
279                         ;
280
281                 switch (*pos) {
282
283                 case ']':
284                         closing_bracket_idx = cbuf_getpos(key);
285                         closing_bracket_pos = pos;
286                         cbuf_putc(key, ']');
287                         pos++;
288                         break;
289
290                 case '\\':
291                         cbuf_putc(key, '\\');
292                         /* n++; */
293                         /* cbuf_puts(subkeyidx, cbuf_getpos(key), sizeof(size_t)) */
294                         while (srprs_char(&pos,'\\'))
295                                 ;
296                         break;
297
298                 case '\0':
299                         if (closing_bracket_pos == NULL) {
300                                 return false;
301                         }
302
303                         /* remove trailing backslash (if any) */
304                         if (*(closing_bracket_pos-1)=='\\') {
305                                 closing_bracket_idx--;
306                         }
307
308                         cbuf_setpos(key, closing_bracket_idx);
309                         *ptr = closing_bracket_pos+1;
310                         return true;
311
312                 default:
313                         assert(false);
314                 }
315         }
316 }
317
318 static bool srprs_val_name(const char** ptr, cbuf* name)
319 {
320         const char* pos = *ptr;
321         const size_t spos = cbuf_getpos(name);
322
323         if ( !srprs_skipws(&pos) ) {
324                 goto fail;
325         }
326
327         if ( srprs_char(&pos, '@') ) {
328                 cbuf_puts(name, "", -1);
329         }
330         else if (!srprs_quoted_string(&pos, name, NULL)) {
331                 goto fail;
332         }
333
334         if (!srprs_skipws(&pos) || !srprs_char(&pos, '=')) {
335                 goto fail;
336         }
337
338         *ptr = pos;
339         return true;
340
341 fail:
342         cbuf_setpos(name, spos);
343         return false;
344 }
345
346 static bool srprs_val_dword(const char** ptr, uint32_t* type, uint32_t* val)
347 {
348         const char* pos = *ptr;
349
350         if (!srprs_str(&pos, "dword:", -1)) {
351                 return false;
352         }
353
354         if (!srprs_hex(&pos, 8, val)) {
355                 return false;
356         }
357
358         *type = REG_DWORD;
359         *ptr  = pos;
360         return true;
361 }
362
363 static bool srprs_val_sz(const char** ptr, uint32_t* type, cbuf* val, bool* cont)
364 {
365         if (!srprs_quoted_string(ptr, val, cont)) {
366                 return false;
367         }
368
369         *type = REG_SZ;
370         return true;
371 }
372
373
374 static bool srprs_nl_no_eos(const char** ptr, cbuf* str, bool eof)
375 {
376         const char* pos = *ptr;
377         const size_t spos = cbuf_getpos(str);
378
379         if( srprs_nl(&pos, str) && (eof || *pos != '\0')) {
380                 *ptr = pos;
381                 return true;
382         }
383         cbuf_setpos(str, spos);
384         return false;
385 }
386
387
388 static bool srprs_eol_cont(const char** ptr, bool* cont)
389 {
390         const char* pos = *ptr;
391         bool bs = srprs_char(&pos, '\\');
392
393         if (!srprs_eol(&pos, NULL)) {
394                 return false;
395         }
396
397         *cont = bs;
398         *ptr = pos;
399         return true;
400 }
401
402 /* matches the empty string, for zero length lists */
403 static bool srprs_val_hex_values(const char** ptr, cbuf* val, bool* cont)
404 {
405         const char* pos = *ptr;
406         unsigned u;
407
408         do {
409                 if (!srprs_skipws(&pos) || !srprs_hex(&pos, 2, &u) || !srprs_skipws(&pos)) {
410                         break;
411                 }
412                 cbuf_putc(val, (char)u);
413         } while(srprs_char(&pos, ','));
414
415         *ptr = pos;
416
417         if (srprs_skipws(&pos) && srprs_eol_cont(&pos, cont)) {
418                 *ptr = pos;
419         }
420
421         return true;
422 }
423
424 static bool srprs_val_hex(const char** ptr, uint32_t* ptype, cbuf* val,
425                        bool* cont)
426 {
427         const char* pos = *ptr;
428         uint32_t type;
429
430         if (!srprs_str(&pos, "hex", -1)) {
431                 return false;
432         }
433
434         if (srprs_char(&pos, ':')) {
435                 type = REG_BINARY;
436         }
437         else if (!srprs_char(&pos, '(') ||
438                  !srprs_hex(&pos, 8, &type) ||
439                  !srprs_char(&pos,')') ||
440                  !srprs_char(&pos, ':'))
441         {
442                 return false;
443         }
444
445         if (!srprs_val_hex_values(&pos, val, cont)) {
446                 return false;
447         }
448
449         *ptype = type;
450         *ptr = pos;
451         return true;
452 }
453
454
455 static bool srprs_comment(const char** ptr, cbuf* str)
456 {
457         return srprs_char(ptr, ';') && srprs_line(ptr, str);
458 }
459
460 /**@}*/
461
462 int reg_parse_set_options(struct reg_parse* parser, const char* options)
463 {
464         static const char* DEFAULT ="enc=unix,flags=0";
465
466         int ret = 0;
467         char *key, *val;
468         void* ctx = talloc_new(parser);
469
470         if (options == NULL) {
471                 options = DEFAULT;
472         }
473
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)) {
477                         char* end = NULL;
478                         if (val != NULL) {
479                                 parser->flags = strtol(val, &end, 0);
480                         }
481                         if ((end==NULL) || (*end != '\0')) {
482                                 DEBUG(0, ("Invalid flags format: %s\n",
483                                           val ? val : "<NULL>"));
484                                 ret = -1;
485                         }
486                 }
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; */
494                 /*      } else { */
495                 /*              DEBUG(0, ("Invalid hive format: %s\n", val)); */
496                 /*              ret = -1; */
497                 /*      } */
498                 /* } */
499         }
500         talloc_free(ctx);
501         return ret;
502 }
503
504
505 int reg_parse_line(struct reg_parse* parser, const char* line)
506 {
507         const char* pos;
508         bool del=false;
509         cbuf* tmp=cbuf_clear(parser->tmp);
510         bool cb_ok = true;
511         bool cont = true;
512
513         if (!line) {
514                 return -4;
515         }
516
517         parser->linenum++;
518         pos = line;
519
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);
524                 }
525                 goto done;
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);
529                 }
530                 goto done;
531         default:
532                 cont = false;
533         }
534
535         if ( !srprs_skipws(&pos) ) {
536                 return -4;
537         }
538
539         /* empty line ?*/
540         if ( srprs_eol(&pos, NULL) ) {
541                 return 0;
542         }
543
544         /* key line ?*/
545         else if (srprs_key(&pos, tmp, &del)) {
546                 cb_ok = act_key(parser, tmp, del);
547         }
548
549         /* comment line ? */
550         else if (srprs_comment(&pos, tmp)) {
551                 cb_ok = act_comment(parser, cbuf_gets(tmp, 0));
552         }
553
554         /* head line */
555         else if ((parser->linenum == 1) && srprs_line(&pos, tmp) ) {
556                 /* cb_ok = act_head(parser, cbuf_gets(tmp, 0)); */
557         }
558
559         /* value line ?*/
560         else if (srprs_val_name(&pos, tmp)) {
561                 uint32_t dw;
562                 cbuf_swap(parser->valname, tmp);
563                 cbuf_clear(tmp);
564
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));
568                         return -3;
569                 }
570
571                 if (!srprs_skipws(&pos)) {
572                         return -4;
573                 }
574
575                 if (srprs_char(&pos, '-')) {
576                         cb_ok = act_val_del(parser);
577                 }
578                 else if (srprs_val_dword(&pos, &parser->valtype, &dw)) {
579                         cb_ok = act_val_dw(parser, dw);
580                 }
581                 else if (srprs_val_sz(&pos, &parser->valtype, tmp, &cont)) {
582                         cb_ok = act_val_sz(parser, tmp, cont);
583                 }
584                 else if (srprs_val_hex(&pos, &parser->valtype, tmp, &cont)){
585                         cb_ok = act_val_hex(parser, tmp, cont);
586                 }
587                 else {
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));
592                         return -3;
593                 }
594         }
595         else {
596                 DEBUG(0, ("unrecognized line %i : %s\n", parser->linenum, line));
597                 return -3;
598         }
599
600 done:
601         if (!cb_ok)
602                 return -2;
603
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));
607                 return -1;
608         }
609         return 0;
610 }
611
612 /******************************************************************************/
613 /**
614  * @addtogroup misc
615  * @{
616  */
617 static bool lookslike_utf16(const char* line, size_t len, bool* little_endian)
618 {
619         static const uint16_t M_LE = 0xFF80;
620         static const uint16_t M_BE = 0x80FF;
621         uint16_t mask;
622         bool le;
623
624         size_t l = MIN(len/2, 64);
625         uint16_t* u = (uint16_t*)line;
626         int i;
627
628         assert(len >= 2);
629
630         if ( u[0] & M_LE ) {
631                 le = true;
632                 mask = M_LE;
633         } else  if ( u[0] & M_BE ) {
634                 le = false;
635                 mask = M_BE;
636         } else {
637                 return false;
638         }
639
640         for (i=1; i<l; i++) {
641                 if ( u[i] & mask ) {
642                         return false;
643                 }
644         }
645
646         *little_endian = le;
647         return true;
648 }
649
650 static bool lookslike_dos(const char* line, size_t len)
651 {
652         int i;
653         for (i=0; i<len; i++) {
654                 if ( (line[i] == '\0') || (line[i] & 0x80) ) {
655                         return false;
656                 }
657                 if ( (line[i] == '\r') && (i+1 < len) && (line[i+1] == '\n') ) {
658                         return true;
659                 }
660         }
661         return false;
662 }
663
664 static bool guess_charset(const char** ptr,
665                           size_t* len,
666                           const char** file_enc,
667                           const char** str_enc)
668 {
669         const char* charset = NULL;
670         const char* pos = *ptr;
671
672         if (*len < 4) {
673                 return false;
674         }
675
676         if (srprs_bom(&pos, &charset, NULL)) {
677                 *len -= (pos - *ptr);
678                 *ptr = pos;
679                 if (*file_enc == NULL) {
680                         *file_enc = charset;
681                 }
682                 else if( strcmp(*file_enc, charset) != 0 ) {
683                         DEBUG(0, ("file encoding forced to %s\n",
684                                   *file_enc));
685                 }
686         }
687         else if (*file_enc == NULL) {
688                 bool le;
689                 if (lookslike_utf16(*ptr, *len, &le)) {
690                         *file_enc = le ? "UTF-16LE" : "UTF-16BE";
691                 }
692                 else if (lookslike_dos(*ptr, *len)) {
693                         *file_enc = "dos";
694                 }
695                 else {
696                         *file_enc = "unix";
697                 }
698         }
699
700         if ((str_enc != NULL) && (*str_enc == NULL)) {
701                 *str_enc = ( strncmp(*ptr, "REGEDIT4", 8) == 0)
702                         ? *file_enc
703                         : "UTF-16LE";
704         }
705
706         return true;
707 }
708 /**@}*/
709
710 struct reg_parse_fd_opt {
711         const char* file_enc;
712         const char* str_enc;
713         unsigned flags;
714         int fail_level;
715 };
716
717 static struct reg_parse_fd_opt
718 reg_parse_fd_opt(void* mem_ctx, const char* options)
719 {
720         struct reg_parse_fd_opt ret = {
721                 .file_enc = NULL,
722                 .str_enc  = NULL,
723                 .flags    = 0,
724         };
725
726         void* ctx = talloc_new(mem_ctx);
727         char *key, *val;
728
729         if (options == NULL) {
730                 goto done;
731         }
732
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)) {
742                         char* end = NULL;
743                         if (val != NULL) {
744                                 ret.flags = strtol(val, &end, 0);
745                         }
746                         if ((end==NULL) || (*end != '\0')) {
747                                 DEBUG(0, ("Invalid format \"%s\": %s\n",
748                                           key, val ? val : "<NULL>"));
749                         }
750                 } else if ((strcmp(key, "fail") == 0) && (val != NULL)) {
751                         char* end = NULL;
752                         if (val != NULL) {
753                                 ret.fail_level = -strtol(val, &end, 0);
754                         }
755                         if ((end==NULL) || (*end != '\0')) {
756                                 DEBUG(0, ("Invalid format \"%s\": %s\n",
757                                           key, val ? val : "<NULL>"));
758                         }
759                 }
760         }
761 done:
762         talloc_free(ctx);
763         return ret;
764 }
765
766
767 static void
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)
771 {
772         const char *pos = obuf;
773         const char *ptr = obuf;
774         switch(err) {
775         case EINVAL:
776                 /* DEBUG(0, ("Incomplete multibyte sequence\n")); */
777         case E2BIG:
778                 return;
779         case EILSEQ:
780                 break;
781         default:
782                 assert(false);
783         }
784
785         **optr = '\0';
786         while (srprs_line(&ptr, NULL) && srprs_nl(&ptr, NULL)) {
787                 pos = ptr;
788                 linenum++;
789         }
790         if (pos == *optr) {
791                 pos = MAX(obuf, *optr-60);
792         }
793         DEBUG(0, ("Illegal multibyte sequence at line %lu: %s",
794                   (long unsigned)(linenum+1), pos));
795
796         assert(ilen > 0);
797         do {
798                 size_t il = 1;
799                 DEBUGADD(0, ("<%02x>", (unsigned char)**iptr));
800
801                 if (olen > 0) {
802                         *(*optr)++ = '\?';
803                         (*iptr)++;
804                         /* Todo: parametrize, e.g. skip: *optr++ = *iptr++; */
805                         (*ilen)--;
806                 }
807
808                 if (smb_iconv(cd, iptr, &il, optr, olen) != (size_t)-1 || (errno != EILSEQ)) {
809                         if(il == 0)
810                                 (*ilen)-- ;
811                         break;
812                 }
813
814         }
815         while ((*ilen > 0) && (*olen > 0));
816
817         DEBUGADD(0, ("\n"));
818
819 }
820
821 int reg_parse_fd(int fd, const struct reg_parse_callback* cb, const char* opts)
822 {
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;
827         char buf_raw[1024];
828         char buf_unix[1025];
829
830         ssize_t nread;
831         size_t  nconv;
832         const char* pos;
833         const char* iptr;
834         char* optr;
835         size_t ilen;
836         size_t olen;
837         int ret = -1;
838         bool eof = false;
839         size_t linenum = 0;
840
841         struct reg_parse_fd_opt opt = reg_parse_fd_opt(mem_ctx, opts);
842
843         if (cb == NULL) {
844                 DEBUG(0,("reg_parse_fd: NULL callback\n"));
845                 goto done;
846         }
847
848         nread = read(fd, buf_raw, sizeof(buf_raw));
849         if (nread < 0) {
850                 DEBUG(0, ("reg_parse_fd: read failed: %s\n", strerror(errno)));
851                 ret = nread;
852                 goto done;
853         }
854
855         iptr = &buf_raw[0];
856         ilen = nread;
857
858         if (!guess_charset(&iptr, &ilen,
859                            &opt.file_enc, &opt.str_enc))
860         {
861                 DEBUG(0, ("reg_parse_fd: failed to guess encoding\n"));
862                 goto done;
863         }
864
865         DEBUG(10, ("reg_parse_fd: encoding file: %s str: %s\n",
866                   opt.file_enc, opt.str_enc));
867
868
869         if (!set_iconv(&cd, "unix", opt.file_enc)) {
870                 DEBUG(0, ("reg_parse_fd: failed to set file encoding %s\n",
871                           opt.file_enc));
872                 goto done;
873         }
874
875         parser = reg_parse_new(mem_ctx, *cb, opt.str_enc, opt.flags);
876
877         optr = &buf_unix[0];
878         while (!eof) {
879                 olen = sizeof(buf_unix) - (optr - buf_unix) - 1 ;
880                 while ( olen > 0 ) {
881                         memmove(buf_raw, iptr, ilen);
882
883                         nread = read(fd, buf_raw + ilen, sizeof(buf_raw) - ilen);
884                         if (nread < 0) {
885                                 DEBUG(0, ("reg_parse_fd: read failed: %s\n", strerror(errno)));
886                                 ret = nread;
887                                 goto done;
888                         }
889
890                         iptr =  buf_raw;
891                         ilen += nread;
892
893                         if (ilen == 0) {
894                                 smb_iconv(cd, NULL, NULL, &optr, &olen);
895                                 eof = true;
896                                 break;
897                         }
898
899                         nconv = smb_iconv(cd, &iptr, &ilen, &optr, &olen);
900
901                         if (nconv == (size_t)-1) {
902                                 handle_iconv_errno(errno, buf_unix, linenum,
903                                                    cd, &iptr, &ilen,
904                                                    &optr, &olen);
905                                 break;
906                         }
907                 }
908         /* process_lines: */
909                 *optr = '\0';
910                 pos = &buf_unix[0];
911
912                 while ( srprs_line(&pos, line) && srprs_nl_no_eos(&pos, line, eof)) {
913                         linenum ++;
914                         ret = reg_parse_line(parser, cbuf_gets(line, 0));
915                         if (ret < opt.fail_level) {
916                                 goto done;
917                         }
918                         cbuf_clear(line);
919                 }
920                 memmove(buf_unix, pos, optr - pos);
921                 optr -= (pos - buf_unix);
922         }
923
924         ret = 0;
925 done:
926         set_iconv(&cd, NULL, NULL);
927         talloc_free(mem_ctx);
928         return ret;
929 }
930
931 int reg_parse_file(const char* fname, const struct reg_parse_callback* cb,
932                    const char* opt)
933 {
934         int ret = -1;
935         int fd;
936
937         fd = open(fname, O_RDONLY);
938         if (fd < 0) {
939                 DEBUG(0, ("reg_parse_file: open failed: %s\n", strerror(errno)));
940                 return -1;
941         }
942
943         ret = reg_parse_fd(fd, cb, opt);
944
945         close(fd);
946         return ret;
947 }
948
949 /* static struct registry_key *find_regkey_by_hnd(pipes_struct *p, */
950 /*                                             struct policy_handle *hnd) */
951 /* { */
952 /*      struct registry_key *regkey = NULL; */
953
954 /*      if(!find_policy_by_hnd(p,hnd,(void **)(void *)&regkey)) { */
955 /*              DEBUG(2,("find_regkey_index_by_hnd: Registry Key not found: ")); */
956 /*              return NULL; */
957 /*      } */
958
959 /*      return regkey; */
960 /* } */