Line data Source code
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 <talloc.h>
38 : #include <stdbool.h>
39 : #include <string.h>
40 : #include <regex.h>
41 : #include <assert.h>
42 : #include <stdint.h>
43 :
44 : enum reg_parse_state {
45 : STATE_DEFAULT,
46 : STATE_KEY_OPEN,
47 : STATE_VAL_HEX_CONT,
48 : STATE_VAL_SZ_CONT
49 : };
50 :
51 : struct reg_parse {
52 : struct reg_format_callback reg_format_callback;
53 : cbuf* key;
54 : cbuf* valname;
55 : uint32_t valtype;
56 : cbuf* valblob;
57 : cbuf* tmp;
58 : struct reg_parse_callback call;
59 : int ret;
60 : int linenum;
61 : enum reg_parse_state state;
62 : struct reg_parse_options* opt;
63 : smb_iconv_t str2UTF16;
64 : unsigned flags;
65 : };
66 :
67 : /**
68 : * @defgroup action Action
69 : * @{
70 : */
71 250 : static bool act_key(struct reg_parse* p, cbuf* keyname, bool del)
72 : {
73 250 : const char* name = cbuf_gets(keyname, 0);
74 250 : cbuf_swap(p->key, keyname);
75 :
76 250 : assert(p->state == STATE_DEFAULT || p->state == STATE_KEY_OPEN);
77 250 : p->state = del ? STATE_DEFAULT : STATE_KEY_OPEN;
78 :
79 250 : assert(p->call.key);
80 250 : p->ret = p->call.key(p->call.data, &name, 1, del);
81 250 : return p->ret >= 0;
82 : }
83 :
84 1136 : static bool value_callback(struct reg_parse* p)
85 : {
86 1136 : const char* name = cbuf_gets(p->valname,0);
87 1136 : const uint8_t* val = (const uint8_t*)cbuf_gets(p->valblob,0);
88 1136 : size_t len = cbuf_getpos(p->valblob);
89 :
90 1136 : assert(p->call.val);
91 1136 : p->ret = p->call.val(p->call.data, name, p->valtype, val, len);
92 1136 : return p->ret >= 0;
93 : }
94 :
95 0 : static bool act_val_hex(struct reg_parse* p, cbuf* value, bool cont)
96 : {
97 0 : cbuf_swap(p->valblob, value);
98 0 : assert((p->state == STATE_KEY_OPEN) || (p->state == STATE_VAL_HEX_CONT));
99 :
100 0 : if (cont) {
101 0 : p->state = STATE_VAL_HEX_CONT;
102 : } else {
103 0 : p->state = STATE_KEY_OPEN;
104 :
105 0 : switch (p->valtype) {
106 0 : case REG_EXPAND_SZ:
107 : case REG_MULTI_SZ:
108 0 : if (p->str2UTF16 != NULL) {
109 0 : char* dst = NULL;
110 0 : const char* src = cbuf_gets(p->valblob, 0);
111 0 : const size_t slen = cbuf_getpos(p->valblob);
112 0 : size_t dlen = iconvert_talloc(p,
113 : p->str2UTF16,
114 : src, slen,
115 : &dst);
116 0 : if (dlen != -1) {
117 0 : cbuf_swapptr(p->valblob, &dst, dlen);
118 : } else {
119 0 : DEBUG(0, ("iconvert_talloc failed\n"));
120 0 : return false;
121 : }
122 0 : talloc_free(dst);
123 : }
124 0 : break;
125 0 : default:
126 0 : break;
127 : }
128 0 : return value_callback(p);
129 : }
130 0 : return true;
131 : }
132 :
133 0 : static bool act_val_dw(struct reg_parse* p, uint32_t val)
134 : {
135 0 : assert(p->valtype == REG_DWORD);
136 0 : assert(p->state == STATE_KEY_OPEN);
137 :
138 0 : cbuf_clear(p->valblob);
139 :
140 0 : if (cbuf_putdw(p->valblob, val) < 0) {
141 0 : return false;
142 : }
143 0 : return value_callback(p);
144 : }
145 :
146 1136 : static bool act_val_sz(struct reg_parse* p, cbuf* value, bool cont)
147 : {
148 1136 : cbuf_swap(p->valblob, value);
149 :
150 1136 : assert(p->valtype == REG_SZ);
151 1136 : assert((p->state == STATE_KEY_OPEN) || (p->state == STATE_VAL_SZ_CONT));
152 :
153 1136 : if (cont) {
154 0 : p->state = STATE_VAL_SZ_CONT;
155 : } else {
156 1136 : char* dst = NULL;
157 0 : size_t dlen;
158 1136 : const char* src = cbuf_gets(p->valblob, 0);
159 :
160 1136 : p->state = STATE_KEY_OPEN;
161 :
162 :
163 1136 : if (convert_string_talloc(p->valblob, CH_UNIX, CH_UTF16LE,
164 1136 : src, strlen(src)+1,
165 : &dst, &dlen))
166 : {
167 1136 : cbuf_swapptr(p->valblob, &dst, dlen);
168 : } else {
169 0 : DEBUG(0, ("convert_string_talloc failed: >%s<\n"
170 : "use it as is\t", src));
171 0 : return false;
172 : }
173 1136 : talloc_free(dst);
174 :
175 1136 : return value_callback(p);
176 : }
177 0 : return true;
178 : }
179 :
180 0 : static bool act_val_del(struct reg_parse* p)
181 : {
182 0 : const char* name = cbuf_gets(p->valname, 0);
183 :
184 0 : assert(p->call.val_del);
185 0 : p->ret = p->call.val_del(p->call.data, name);
186 0 : return p->ret >= 0;
187 : }
188 :
189 8 : static bool act_comment (struct reg_parse* p, const char* txt)
190 : {
191 8 : assert(p->call.comment);
192 8 : p->ret = p->call.comment(p->call.data, txt);
193 8 : return p->ret >= 0;
194 : }
195 : /**@}*/
196 :
197 :
198 0 : static int nop_callback_key(void* private_data,
199 : const char* key[],
200 : size_t klen,
201 : bool del)
202 : {
203 0 : return 0;
204 : }
205 :
206 0 : static int nop_callback_val(void* private_data,
207 : const char* name,
208 : uint32_t type,
209 : const uint8_t* data,
210 : size_t len)
211 : {
212 0 : return 0;
213 : }
214 :
215 0 : static int nop_callback_del(void* data, const char* str)
216 : {
217 0 : return 0;
218 : }
219 :
220 10 : struct reg_parse* reg_parse_new(const void* ctx,
221 : struct reg_parse_callback cb,
222 : const char* str_enc, unsigned flags)
223 : {
224 10 : struct reg_parse* s = talloc_zero(ctx, struct reg_parse);
225 10 : if (s == NULL)
226 0 : return NULL;
227 10 : s->key = cbuf_new(s);
228 10 : s->valname = cbuf_new(s);
229 10 : s->valblob = cbuf_new(s);
230 10 : s->tmp = cbuf_new(s);
231 10 : if ( (s->tmp == NULL) || (s->valblob == NULL)
232 10 : || (s->valname == NULL) || (s->key == NULL) )
233 : {
234 0 : goto fail;
235 : }
236 :
237 10 : s->reg_format_callback.writeline = (reg_format_callback_writeline_t)®_parse_line;
238 10 : s->reg_format_callback.data = s;
239 :
240 10 : s->valtype = 0;
241 10 : if (cb.key == NULL) {
242 0 : cb.key = (reg_parse_callback_key_t)&nop_callback_key;
243 : }
244 10 : if (cb.val == NULL) {
245 0 : cb.val = (reg_parse_callback_val_t)&nop_callback_val;
246 : }
247 10 : if (cb.val_del == NULL) {
248 0 : cb.val_del = (reg_parse_callback_val_del_t)&nop_callback_del;
249 : }
250 10 : if (cb.comment == NULL) {
251 0 : cb.comment =
252 : (reg_parse_callback_comment_t)&nop_callback_del;
253 : }
254 :
255 10 : s->call = cb;
256 10 : s->linenum = 0;
257 10 : s->state = STATE_DEFAULT;
258 10 : s->flags = flags;
259 :
260 10 : if (str_enc && !set_iconv(&s->str2UTF16, "UTF-16LE", str_enc)) {
261 0 : DEBUG(0, ("reg_parse_new: failed to set encoding: %s\n",
262 : str_enc));
263 0 : goto fail;
264 : }
265 :
266 : assert(&s->reg_format_callback == (struct reg_format_callback*)s);
267 10 : return s;
268 0 : fail:
269 0 : set_iconv(&s->str2UTF16, NULL, NULL);
270 0 : talloc_free(s);
271 0 : return NULL;
272 : }
273 :
274 : /**
275 : * @defgroup parse Parser Primitive
276 : * @ingroup internal
277 : * @{
278 : */
279 :
280 :
281 1402 : static bool srprs_key(const char** ptr, cbuf* key, bool* del)
282 : {
283 1402 : const char* pos = *ptr;
284 1402 : const char* closing_bracket_pos = NULL;
285 1402 : size_t closing_bracket_idx = 0;
286 :
287 1402 : if (!srprs_skipws(&pos) || !srprs_char(&pos, '[')) {
288 1152 : return false;
289 : }
290 :
291 250 : *del = srprs_char(&pos, '-');
292 :
293 250 : cbuf_clear(key);
294 :
295 : while (true) {
296 10822 : while (srprs_charsetinv(&pos, "]\\", key))
297 : ;
298 :
299 1452 : switch (*pos) {
300 :
301 250 : case ']':
302 250 : closing_bracket_idx = cbuf_getpos(key);
303 250 : closing_bracket_pos = pos;
304 250 : cbuf_putc(key, ']');
305 250 : pos++;
306 250 : break;
307 :
308 952 : case '\\':
309 952 : cbuf_putc(key, '\\');
310 : /* n++; */
311 : /* cbuf_puts(subkeyidx, cbuf_getpos(key), sizeof(size_t)) */
312 1904 : while (srprs_char(&pos,'\\'))
313 : ;
314 952 : break;
315 :
316 250 : case '\0':
317 250 : if (closing_bracket_pos == NULL) {
318 0 : return false;
319 : }
320 :
321 : /* remove trailing backslash (if any) */
322 250 : if (*(closing_bracket_pos-1)=='\\') {
323 0 : closing_bracket_idx--;
324 : }
325 :
326 250 : cbuf_setpos(key, closing_bracket_idx);
327 250 : *ptr = closing_bracket_pos+1;
328 250 : return true;
329 :
330 0 : default:
331 0 : assert(false);
332 : }
333 : }
334 : }
335 :
336 1136 : static bool srprs_val_name(const char** ptr, cbuf* name)
337 : {
338 1136 : const char* pos = *ptr;
339 1136 : const size_t spos = cbuf_getpos(name);
340 :
341 1136 : if ( !srprs_skipws(&pos) ) {
342 0 : goto fail;
343 : }
344 :
345 1136 : if ( srprs_char(&pos, '@') ) {
346 0 : cbuf_puts(name, "", -1);
347 : }
348 1136 : else if (!srprs_quoted_string(&pos, name, NULL)) {
349 0 : goto fail;
350 : }
351 :
352 1136 : if (!srprs_skipws(&pos) || !srprs_char(&pos, '=')) {
353 0 : goto fail;
354 : }
355 :
356 1136 : *ptr = pos;
357 1136 : return true;
358 :
359 0 : fail:
360 0 : cbuf_setpos(name, spos);
361 0 : return false;
362 : }
363 :
364 1136 : static bool srprs_val_dword(const char** ptr, uint32_t* type, uint32_t* val)
365 : {
366 1136 : const char* pos = *ptr;
367 :
368 1136 : if (!srprs_str(&pos, "dword:", -1)) {
369 1136 : return false;
370 : }
371 :
372 0 : if (!srprs_hex(&pos, 8, val)) {
373 0 : return false;
374 : }
375 :
376 0 : *type = REG_DWORD;
377 0 : *ptr = pos;
378 0 : return true;
379 : }
380 :
381 1136 : static bool srprs_val_sz(const char** ptr, uint32_t* type, cbuf* val, bool* cont)
382 : {
383 1136 : if (!srprs_quoted_string(ptr, val, cont)) {
384 0 : return false;
385 : }
386 :
387 1136 : *type = REG_SZ;
388 1136 : return true;
389 : }
390 :
391 :
392 1723 : static bool srprs_nl_no_eos(const char** ptr, cbuf* str, bool eof)
393 : {
394 1723 : const char* pos = *ptr;
395 1723 : const size_t spos = cbuf_getpos(str);
396 :
397 1723 : if( srprs_nl(&pos, str) && (eof || *pos != '\0')) {
398 1654 : *ptr = pos;
399 1654 : return true;
400 : }
401 69 : cbuf_setpos(str, spos);
402 69 : return false;
403 : }
404 :
405 :
406 0 : static bool srprs_eol_cont(const char** ptr, bool* cont)
407 : {
408 0 : const char* pos = *ptr;
409 0 : bool bs = srprs_char(&pos, '\\');
410 :
411 0 : if (!srprs_eol(&pos, NULL)) {
412 0 : return false;
413 : }
414 :
415 0 : *cont = bs;
416 0 : *ptr = pos;
417 0 : return true;
418 : }
419 :
420 : /* matches the empty string, for zero length lists */
421 0 : static bool srprs_val_hex_values(const char** ptr, cbuf* val, bool* cont)
422 : {
423 0 : const char* pos = *ptr;
424 0 : unsigned u;
425 :
426 0 : do {
427 0 : if (!srprs_skipws(&pos) || !srprs_hex(&pos, 2, &u) || !srprs_skipws(&pos)) {
428 : break;
429 : }
430 0 : cbuf_putc(val, (char)u);
431 0 : } while(srprs_char(&pos, ','));
432 :
433 0 : *ptr = pos;
434 :
435 0 : if (srprs_skipws(&pos) && srprs_eol_cont(&pos, cont)) {
436 0 : *ptr = pos;
437 : }
438 :
439 0 : return true;
440 : }
441 :
442 0 : static bool srprs_val_hex(const char** ptr, uint32_t* ptype, cbuf* val,
443 : bool* cont)
444 : {
445 0 : const char* pos = *ptr;
446 0 : uint32_t type;
447 :
448 0 : if (!srprs_str(&pos, "hex", -1)) {
449 0 : return false;
450 : }
451 :
452 0 : if (srprs_char(&pos, ':')) {
453 0 : type = REG_BINARY;
454 : }
455 0 : else if (!srprs_char(&pos, '(') ||
456 0 : !srprs_hex(&pos, 8, &type) ||
457 0 : !srprs_char(&pos,')') ||
458 0 : !srprs_char(&pos, ':'))
459 : {
460 0 : return false;
461 : }
462 :
463 0 : if (!srprs_val_hex_values(&pos, val, cont)) {
464 0 : return false;
465 : }
466 :
467 0 : *ptype = type;
468 0 : *ptr = pos;
469 0 : return true;
470 : }
471 :
472 :
473 1152 : static bool srprs_comment(const char** ptr, cbuf* str)
474 : {
475 1152 : return srprs_char(ptr, ';') && srprs_line(ptr, str);
476 : }
477 :
478 : /**@}*/
479 :
480 0 : int reg_parse_set_options(struct reg_parse* parser, const char* options)
481 : {
482 0 : static const char* DEFAULT ="enc=unix,flags=0";
483 :
484 0 : int ret = 0;
485 0 : char *key, *val;
486 0 : void* ctx = talloc_new(parser);
487 :
488 0 : if (options == NULL) {
489 0 : options = DEFAULT;
490 : }
491 :
492 0 : while (srprs_option(&options, ctx, &key, &val)) {
493 0 : if ((strcmp(key, "enc") == 0) || (strcmp(key, "strenc") == 0)) {
494 0 : } else if ((strcmp(key, "flags") == 0) && (val != NULL)) {
495 0 : char* end = NULL;
496 0 : if (val != NULL) {
497 0 : parser->flags = strtol(val, &end, 0);
498 : }
499 0 : if ((end==NULL) || (*end != '\0')) {
500 0 : DEBUG(0, ("Invalid flags format: %s\n",
501 : val ? val : "<NULL>"));
502 0 : ret = -1;
503 : }
504 : }
505 : /* else if (strcmp(key, "hive") == 0) { */
506 : /* if (strcmp(val, "short") == 0) { */
507 : /* f->hive_fmt = REG_FMT_SHORT_HIVES; */
508 : /* } else if (strcmp(val, "long") == 0) { */
509 : /* f->hive_fmt = REG_FMT_LONG_HIVES; */
510 : /* } else if (strcmp(val, "preserve") == 0) { */
511 : /* f->hive_fmt = REG_FMT_PRESERVE_HIVES; */
512 : /* } else { */
513 : /* DEBUG(0, ("Invalid hive format: %s\n", val)); */
514 : /* ret = -1; */
515 : /* } */
516 : /* } */
517 : }
518 0 : talloc_free(ctx);
519 0 : return ret;
520 : }
521 :
522 :
523 1654 : int reg_parse_line(struct reg_parse* parser, const char* line)
524 : {
525 0 : const char* pos;
526 1654 : bool del=false;
527 1654 : cbuf* tmp=cbuf_clear(parser->tmp);
528 1654 : bool cb_ok = true;
529 1654 : bool cont = true;
530 :
531 1654 : if (!line) {
532 0 : return -4;
533 : }
534 :
535 1654 : parser->linenum++;
536 1654 : pos = line;
537 :
538 1654 : switch (parser->state) {
539 0 : case STATE_VAL_HEX_CONT:
540 0 : if (srprs_val_hex_values(&pos, parser->valblob, &cont)) {
541 0 : cb_ok = act_val_hex(parser, parser->valblob, cont);
542 : }
543 0 : goto done;
544 0 : case STATE_VAL_SZ_CONT:
545 0 : if (srprs_quoted_string(&pos, parser->valblob, &cont)) {
546 0 : cb_ok = act_val_sz(parser, parser->valblob, cont);
547 : }
548 0 : goto done;
549 1654 : default:
550 1654 : cont = false;
551 : }
552 :
553 1654 : if ( !srprs_skipws(&pos) ) {
554 0 : return -4;
555 : }
556 :
557 : /* empty line ?*/
558 1654 : if ( srprs_eol(&pos, NULL) ) {
559 252 : return 0;
560 : }
561 :
562 : /* key line ?*/
563 1402 : else if (srprs_key(&pos, tmp, &del)) {
564 250 : cb_ok = act_key(parser, tmp, del);
565 : }
566 :
567 : /* comment line ? */
568 1152 : else if (srprs_comment(&pos, tmp)) {
569 8 : cb_ok = act_comment(parser, cbuf_gets(tmp, 0));
570 : }
571 :
572 : /* head line */
573 1144 : else if ((parser->linenum == 1) && srprs_line(&pos, tmp) ) {
574 : /* cb_ok = act_head(parser, cbuf_gets(tmp, 0)); */
575 : }
576 :
577 : /* value line ?*/
578 1136 : else if (srprs_val_name(&pos, tmp)) {
579 0 : uint32_t dw;
580 1136 : cbuf_swap(parser->valname, tmp);
581 1136 : cbuf_clear(tmp);
582 :
583 1136 : if (parser->state != STATE_KEY_OPEN) {
584 0 : DEBUG(0, ("value \"%s\" without a key at line: %i\n",
585 : cbuf_gets(parser->valname, 0), parser->linenum));
586 0 : return -3;
587 : }
588 :
589 1136 : if (!srprs_skipws(&pos)) {
590 0 : return -4;
591 : }
592 :
593 1136 : if (srprs_char(&pos, '-')) {
594 0 : cb_ok = act_val_del(parser);
595 : }
596 1136 : else if (srprs_val_dword(&pos, &parser->valtype, &dw)) {
597 0 : cb_ok = act_val_dw(parser, dw);
598 : }
599 1136 : else if (srprs_val_sz(&pos, &parser->valtype, tmp, &cont)) {
600 1136 : cb_ok = act_val_sz(parser, tmp, cont);
601 : }
602 0 : else if (srprs_val_hex(&pos, &parser->valtype, tmp, &cont)){
603 0 : cb_ok = act_val_hex(parser, tmp, cont);
604 : }
605 : else {
606 0 : DEBUG(0, ("value \"%s\" parse error"
607 : "at line: %i pos: %li : %s\n",
608 : cbuf_gets(parser->valname, 0), parser->linenum,
609 : (long int)(pos-line), pos));
610 0 : return -3;
611 : }
612 : }
613 : else {
614 0 : DEBUG(0, ("unrecognized line %i : %s\n", parser->linenum, line));
615 0 : return -3;
616 : }
617 :
618 1402 : done:
619 1402 : if (!cb_ok)
620 2 : return -2;
621 :
622 1400 : if (!srprs_skipws(&pos) || !srprs_eol(&pos, NULL)) {
623 0 : DEBUG(0, ("trailing garbage at line: %i pos: %li : %s\n",
624 : parser->linenum, (long int)(pos-line), pos));
625 0 : return -1;
626 : }
627 1400 : return 0;
628 : }
629 :
630 : /******************************************************************************/
631 : /**
632 : * @addtogroup misc
633 : * @{
634 : */
635 8 : static bool lookslike_utf16(const char* line, size_t len, bool* little_endian)
636 : {
637 0 : static const uint16_t M_LE = 0xFF80;
638 0 : static const uint16_t M_BE = 0x80FF;
639 0 : uint16_t mask;
640 0 : bool le;
641 :
642 8 : size_t l = MIN(len/2, 64);
643 8 : const uint16_t* u = (const uint16_t*)line;
644 0 : size_t i;
645 :
646 8 : assert(len >= 2);
647 :
648 8 : if ( u[0] & M_LE ) {
649 8 : le = true;
650 8 : mask = M_LE;
651 0 : } else if ( u[0] & M_BE ) {
652 0 : le = false;
653 0 : mask = M_BE;
654 : } else {
655 0 : return false;
656 : }
657 :
658 8 : for (i=1; i<l; i++) {
659 8 : if ( u[i] & mask ) {
660 8 : return false;
661 : }
662 : }
663 :
664 0 : *little_endian = le;
665 0 : return true;
666 : }
667 :
668 8 : static bool lookslike_dos(const char* line, size_t len)
669 : {
670 : size_t i;
671 6152 : for (i=0; i<len; i++) {
672 6146 : if ( (line[i] == '\0') || (line[i] & 0x80) ) {
673 2 : return false;
674 : }
675 6144 : if ( (line[i] == '\r') && (i+1 < len) && (line[i+1] == '\n') ) {
676 0 : return true;
677 : }
678 : }
679 6 : return false;
680 : }
681 :
682 10 : static bool guess_charset(const char** ptr,
683 : size_t* len,
684 : const char** file_enc,
685 : const char** str_enc)
686 : {
687 10 : const char* charset = NULL;
688 10 : const char* pos = *ptr;
689 :
690 10 : if (*len < 4) {
691 0 : return false;
692 : }
693 :
694 10 : if (srprs_bom(&pos, &charset, NULL)) {
695 0 : size_t declen;
696 2 : if (pos < *ptr) {
697 0 : return false;
698 : }
699 2 : declen = (pos - *ptr);
700 2 : if (*len < declen) {
701 0 : return false;
702 : }
703 2 : *len -= declen;
704 2 : *ptr = pos;
705 2 : if (*file_enc == NULL) {
706 2 : *file_enc = charset;
707 : }
708 0 : else if( strcmp(*file_enc, charset) != 0 ) {
709 0 : DEBUG(0, ("file encoding forced to %s\n",
710 : *file_enc));
711 : }
712 : }
713 8 : else if (*file_enc == NULL) {
714 0 : bool le;
715 8 : if (lookslike_utf16(*ptr, *len, &le)) {
716 0 : *file_enc = le ? "UTF-16LE" : "UTF-16BE";
717 : }
718 8 : else if (lookslike_dos(*ptr, *len)) {
719 0 : *file_enc = "dos";
720 : }
721 : else {
722 8 : *file_enc = "unix";
723 : }
724 : }
725 :
726 10 : if ((str_enc != NULL) && (*str_enc == NULL)) {
727 10 : *str_enc = ( strncmp(*ptr, "REGEDIT4", 8) == 0)
728 : ? *file_enc
729 10 : : "UTF-16LE";
730 : }
731 :
732 10 : return true;
733 : }
734 : /**@}*/
735 :
736 : struct reg_parse_fd_opt {
737 : const char* file_enc;
738 : const char* str_enc;
739 : unsigned flags;
740 : int fail_level;
741 : };
742 :
743 : static struct reg_parse_fd_opt
744 10 : reg_parse_fd_opt(void* mem_ctx, const char* options)
745 : {
746 10 : struct reg_parse_fd_opt ret = {
747 : .file_enc = NULL,
748 : .str_enc = NULL,
749 : .flags = 0,
750 : };
751 :
752 10 : void* ctx = talloc_new(mem_ctx);
753 0 : char *key, *val;
754 :
755 10 : if (options == NULL) {
756 10 : goto done;
757 : }
758 :
759 0 : while (srprs_option(&options, ctx, &key, &val)) {
760 0 : if (strcmp(key, "enc") == 0) {
761 0 : ret.file_enc = talloc_steal(mem_ctx, val);
762 0 : ret.str_enc = ret.file_enc;
763 0 : } else if (strcmp(key, "strenc") == 0) {
764 0 : ret.str_enc = talloc_steal(mem_ctx, val);
765 0 : } else if (strcmp(key, "fileenc") == 0) {
766 0 : ret.file_enc = talloc_steal(mem_ctx, val);
767 0 : } else if ((strcmp(key, "flags") == 0) && (val != NULL)) {
768 0 : char* end = NULL;
769 0 : if (val != NULL) {
770 0 : ret.flags = strtol(val, &end, 0);
771 : }
772 0 : if ((end==NULL) || (*end != '\0')) {
773 0 : DEBUG(0, ("Invalid format \"%s\": %s\n",
774 : key, val ? val : "<NULL>"));
775 : }
776 0 : } else if ((strcmp(key, "fail") == 0) && (val != NULL)) {
777 0 : char* end = NULL;
778 0 : if (val != NULL) {
779 0 : ret.fail_level = -strtol(val, &end, 0);
780 : }
781 0 : if ((end==NULL) || (*end != '\0')) {
782 0 : DEBUG(0, ("Invalid format \"%s\": %s\n",
783 : key, val ? val : "<NULL>"));
784 : }
785 : }
786 : }
787 0 : done:
788 10 : talloc_free(ctx);
789 10 : return ret;
790 : }
791 :
792 2 : static void display_iconv_error_bytes(const char *inbuf, size_t len)
793 : {
794 0 : size_t i;
795 10 : for (i = 0; i < 4 && i < len; i++) {
796 8 : DEBUGADD(0, ("<%02x>", (unsigned char)inbuf[i]));
797 : }
798 2 : DEBUGADD(0, ("\n"));
799 2 : }
800 :
801 10 : int reg_parse_fd(int fd, const struct reg_parse_callback* cb, const char* opts)
802 : {
803 10 : void* mem_ctx = talloc_stackframe();
804 10 : cbuf* line = cbuf_new(mem_ctx);
805 10 : smb_iconv_t cd = (smb_iconv_t)-1;
806 10 : struct reg_parse* parser = NULL;
807 0 : char buf_in[1024];
808 10 : char buf_out[1025] = { 0 };
809 0 : ssize_t nread;
810 0 : const char* iptr;
811 0 : char* optr;
812 0 : size_t ilen;
813 0 : size_t olen;
814 10 : size_t avail_osize = sizeof(buf_out)-1;
815 10 : size_t space_to_read = sizeof(buf_in);
816 10 : int ret = -1;
817 10 : bool eof = false;
818 10 : size_t linecount = 0;
819 :
820 10 : struct reg_parse_fd_opt opt = reg_parse_fd_opt(mem_ctx, opts);
821 :
822 10 : if (cb == NULL) {
823 0 : DBG_ERR("NULL callback\n");
824 0 : ret = -1;
825 0 : goto done;
826 : }
827 :
828 10 : nread = read(fd, buf_in, space_to_read);
829 10 : if (nread < 0) {
830 0 : DBG_ERR("read failed: %s\n", strerror(errno));
831 0 : ret = -1;
832 0 : goto done;
833 : }
834 10 : if (nread == 0) {
835 : /* Empty file. */
836 0 : eof = true;
837 0 : goto done;
838 : }
839 :
840 10 : iptr = buf_in;
841 10 : ilen = nread;
842 :
843 10 : if (!guess_charset(&iptr, &ilen,
844 : &opt.file_enc, &opt.str_enc))
845 : {
846 0 : DBG_ERR("reg_parse_fd: failed to guess encoding\n");
847 0 : ret = -1;
848 0 : goto done;
849 : }
850 :
851 10 : if (ilen == 0) {
852 : /* File only contained charset info. */
853 0 : eof = true;
854 0 : ret = -1;
855 0 : goto done;
856 : }
857 :
858 10 : DBG_DEBUG("reg_parse_fd: encoding file: %s str: %s\n",
859 : opt.file_enc, opt.str_enc);
860 :
861 :
862 10 : if (!set_iconv(&cd, "unix", opt.file_enc)) {
863 0 : DBG_ERR("reg_parse_fd: failed to set file encoding %s\n",
864 : opt.file_enc);
865 0 : ret = -1;
866 0 : goto done;
867 : }
868 :
869 10 : parser = reg_parse_new(mem_ctx, *cb, opt.str_enc, opt.flags);
870 10 : if (parser == NULL) {
871 0 : ret = -1;
872 0 : goto done;
873 : }
874 :
875 : /* Move input data to start of buf_in. */
876 10 : if (iptr > buf_in) {
877 2 : memmove(buf_in, iptr, ilen);
878 2 : iptr = buf_in;
879 : }
880 :
881 10 : optr = buf_out;
882 : /* Leave last byte for null termination. */
883 10 : olen = avail_osize;
884 :
885 : /*
886 : * We read from buf_in (iptr), iconv converting into
887 : * buf_out (optr).
888 : */
889 :
890 79 : while (!eof) {
891 0 : const char *pos;
892 0 : size_t nconv;
893 :
894 73 : if (olen == 0) {
895 : /* We're out of possible room. */
896 0 : DBG_ERR("no room in output buffer\n");
897 0 : ret = -1;
898 4 : goto done;
899 : }
900 73 : nconv = smb_iconv(cd, &iptr, &ilen, &optr, &olen);
901 73 : if (nconv == (size_t)-1) {
902 6 : bool valid_err = false;
903 6 : if (errno == EINVAL) {
904 0 : valid_err = true;
905 : }
906 6 : if (errno == E2BIG) {
907 4 : valid_err = true;
908 : }
909 6 : if (!valid_err) {
910 2 : DBG_ERR("smb_iconv error in file at line %zu: ",
911 : linecount);
912 2 : display_iconv_error_bytes(iptr, ilen);
913 2 : ret = -1;
914 2 : goto done;
915 : }
916 : /*
917 : * For valid errors process the
918 : * existing buffer then continue.
919 : */
920 : }
921 :
922 : /*
923 : * We know this is safe as we have an extra
924 : * enforced zero byte at the end of buf_out.
925 : */
926 71 : *optr = '\0';
927 71 : pos = buf_out;
928 :
929 1723 : while (srprs_line(&pos, line) && srprs_nl_no_eos(&pos, line, eof)) {
930 0 : int retval;
931 :
932 : /* Process all lines we got. */
933 1654 : retval = reg_parse_line(parser, cbuf_gets(line, 0));
934 1654 : if (retval < opt.fail_level) {
935 2 : DBG_ERR("reg_parse_line %zu fail %d\n",
936 : linecount,
937 : retval);
938 2 : ret = -1;
939 2 : goto done;
940 : }
941 1652 : cbuf_clear(line);
942 1652 : linecount++;
943 : }
944 69 : if (pos > buf_out) {
945 : /*
946 : * The output data we have
947 : * processed starts at buf_out
948 : * and ends at pos.
949 : * The unprocessed output
950 : * data starts at pos and
951 : * ends at optr.
952 : *
953 : * <------ sizeof(buf_out) - 1------------->|0|
954 : * <--------- avail_osize------------------>|0|
955 : * +----------------------+-------+-----------+
956 : * | | | |0|
957 : * +----------------------+-------+-----------+
958 : * ^ ^ ^
959 : * | | |
960 : * buf_out pos optr
961 : */
962 0 : size_t unprocessed_len;
963 :
964 : /* Paranoia checks. */
965 69 : if (optr < pos) {
966 0 : ret = -1;
967 0 : goto done;
968 : }
969 69 : unprocessed_len = optr - pos;
970 :
971 : /* Paranoia checks. */
972 69 : if (avail_osize < unprocessed_len) {
973 0 : ret = -1;
974 0 : goto done;
975 : }
976 : /* Move down any unprocessed data. */
977 69 : memmove(buf_out, pos, unprocessed_len);
978 :
979 : /*
980 : * After the move, reset the output length.
981 : *
982 : * <------ sizeof(buf_out) - 1------------->|0|
983 : * <--------- avail_osize------------------>|0|
984 : * +----------------------+-------+-----------+
985 : * | | |0|
986 : * +----------------------+-------+-----------+
987 : * ^ ^
988 : * | optr
989 : * buf_out
990 : */
991 69 : optr = buf_out + unprocessed_len;
992 : /*
993 : * Calculate the new output space available
994 : * for iconv.
995 : * We already did the paranoia check for this
996 : * arithmetic above.
997 : */
998 69 : olen = avail_osize - unprocessed_len;
999 : }
1000 :
1001 : /*
1002 : * Move any unprocessed data to the start of
1003 : * the input buffer (buf_in).
1004 : */
1005 69 : if (ilen > 0 && iptr > buf_in) {
1006 4 : memmove(buf_in, iptr, ilen);
1007 : }
1008 :
1009 : /* Is there any space to read more input ? */
1010 69 : if (ilen >= sizeof(buf_in)) {
1011 : /* No space. Nothing was converted. Error. */
1012 0 : DBG_ERR("no space in input buffer\n");
1013 0 : ret = -1;
1014 0 : goto done;
1015 : }
1016 :
1017 69 : space_to_read = sizeof(buf_in) - ilen;
1018 :
1019 : /* Read the next chunk from the file. */
1020 69 : nread = read(fd, buf_in + ilen, space_to_read);
1021 69 : if (nread < 0) {
1022 0 : DBG_ERR("read failed: %s\n", strerror(errno));
1023 0 : ret = -1;
1024 0 : goto done;
1025 : }
1026 69 : if (nread == 0) {
1027 : /* Empty file. */
1028 6 : eof = true;
1029 6 : continue;
1030 : }
1031 :
1032 : /* Paranoia check. */
1033 63 : if (nread + ilen < ilen) {
1034 0 : ret = -1;
1035 0 : goto done;
1036 : }
1037 :
1038 : /* Paranoia check. */
1039 63 : if (nread + ilen > sizeof(buf_in)) {
1040 0 : ret = -1;
1041 0 : goto done;
1042 : }
1043 :
1044 63 : iptr = buf_in;
1045 63 : ilen = nread + ilen;
1046 : }
1047 :
1048 6 : ret = 0;
1049 :
1050 10 : done:
1051 :
1052 10 : set_iconv(&cd, NULL, NULL);
1053 10 : if (parser) {
1054 10 : set_iconv(&parser->str2UTF16, NULL, NULL);
1055 : }
1056 10 : talloc_free(mem_ctx);
1057 10 : return ret;
1058 : }
1059 :
1060 10 : int reg_parse_file(const char* fname, const struct reg_parse_callback* cb,
1061 : const char* opt)
1062 : {
1063 10 : int ret = -1;
1064 0 : int fd;
1065 :
1066 10 : fd = open(fname, O_RDONLY);
1067 10 : if (fd < 0) {
1068 0 : DEBUG(0, ("reg_parse_file: open %s failed: %s\n", fname,
1069 : strerror(errno)));
1070 0 : return -1;
1071 : }
1072 :
1073 10 : ret = reg_parse_fd(fd, cb, opt);
1074 :
1075 10 : close(fd);
1076 10 : return ret;
1077 : }
1078 :
1079 : /* static struct registry_key *find_regkey_by_hnd(pipes_struct *p, */
1080 : /* struct policy_handle *hnd) */
1081 : /* { */
1082 : /* struct registry_key *regkey = NULL; */
1083 :
1084 : /* if(!find_policy_by_hnd(p,hnd,(void **)(void *)®key)) { */
1085 : /* DEBUG(2,("find_regkey_index_by_hnd: Registry Key not found: ")); */
1086 : /* return NULL; */
1087 : /* } */
1088 :
1089 : /* return regkey; */
1090 : /* } */
|