1 /*
2    Bacula(R) - The Network Backup Solution
3 
4    Copyright (C) 2000-2020 Kern Sibbald
5 
6    The original author of Bacula is Kern Sibbald, with contributions
7    from many others, a complete list can be found in the file AUTHORS.
8 
9    You may use this file and others of this release according to the
10    license defined in the LICENSE file, which includes the Affero General
11    Public License, v3.0 ("AGPLv3") and some additional permissions and
12    terms pursuant to its AGPLv3 Section 7.
13 
14    This notice must be preserved when any source code is
15    conveyed and/or propagated.
16 
17    Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 /*
20  * Lexical scanner for Bacula configuration file
21  *
22  *   Kern Sibbald, 2000
23  *
24  */
25 
26 #include "bacula.h"
27 #include "lex.h"
28 
29 /* Debug level for this source file */
30 static const int dbglvl = 5000;
31 
32 /*
33  * Return false if the end of the line contains anything other
34  *   than spaces, or a semicolon or a comment.
35  */
lex_check_eol(LEX * lf)36 bool lex_check_eol(LEX *lf)
37 {
38    char *ch = lf->line+lf->col_no;
39    while (*ch != '\0' && *ch != '#' && B_ISSPACE(*ch) && *ch != ';') {
40       ch++;
41    }
42    return *ch == '\0' || *ch == '#' || *ch == ';';
43 }
44 
45 /*
46  * Scan to "logical" end of line. I.e. end of line,
47  *   or semicolon, but stop on T_EOB (same as end of
48  *   line except it is not eaten).
49  */
scan_to_eol(LEX * lc)50 void scan_to_eol(LEX *lc)
51 {
52    int token;
53    Dmsg0(dbglvl, "start scan to eol\n");
54    while ((token = lex_get_token(lc, T_ALL)) != T_EOL) {
55       if (token == T_EOB) {
56          lex_unget_char(lc);
57          return;
58       }
59       if (token == T_EOF) {
60          return;
61       }
62    }
63 }
64 
65 /*
66  * Get next token, but skip EOL
67  */
scan_to_next_not_eol(LEX * lc)68 int scan_to_next_not_eol(LEX * lc)
69 {
70    int token;
71    do {
72       token = lex_get_token(lc, T_ALL);
73    } while (token == T_EOL);
74    return token;
75 }
76 
77 /*
78  * Format a scanner error message
79  */
s_err(const char * file,int line,LEX * lc,const char * msg,...)80 static void s_err(const char *file, int line, LEX *lc, const char *msg, ...)
81 {
82    va_list arg_ptr;
83    char buf[MAXSTRING];
84    char more[MAXSTRING];
85 
86    va_start(arg_ptr, msg);
87    bvsnprintf(buf, sizeof(buf), msg, arg_ptr);
88    va_end(arg_ptr);
89 
90    if (lc->err_type == 0) {     /* M_ERROR_TERM by default */
91       lc->err_type = M_ERROR_TERM;
92    }
93 
94    if (lc->line_no > lc->begin_line_no) {
95       bsnprintf(more, sizeof(more),
96                 _("Problem probably begins at line %d.\n"), lc->begin_line_no);
97    } else {
98       more[0] = 0;
99    }
100    if (lc->line_no > 0) {
101       e_msg(file, line, lc->err_type, 0, _("Config error: %s\n"
102 "            : line %d, col %d of file %s\n%s\n%s"),
103          buf, lc->line_no, lc->col_no, lc->fname, lc->line, more);
104    } else {
105       e_msg(file, line, lc->err_type, 0, _("Config error: %s\n"), buf);
106    }
107 }
108 
lex_set_default_error_handler(LEX * lf)109 void lex_set_default_error_handler(LEX *lf)
110 {
111    lf->scan_error = s_err;
112 }
113 
114 /*
115  * Set err_type used in error_handler
116  * return the old value
117  */
lex_set_error_handler_error_type(LEX * lf,int err_type)118 int lex_set_error_handler_error_type(LEX *lf, int err_type)
119 {
120    int old = lf->err_type;
121    lf->err_type = err_type;
122    return old;
123 }
124 
125 /* Store passwords in clear text or with MD5 encoding */
lex_store_clear_passwords(LEX * lf)126 void lex_store_clear_passwords(LEX *lf)
127 {
128    lf->options |= LOPT_NO_MD5;
129 }
130 
131 /*
132  * Free the current file, and retrieve the contents
133  * of the previous packet if any.
134  */
lex_close_file(LEX * lf)135 LEX *lex_close_file(LEX *lf)
136 {
137    LEX *of;
138 
139    if (lf == NULL) {
140       Emsg0(M_ABORT, 0, _("Close of NULL file\n"));
141    }
142    Dmsg1(dbglvl, "Close lex file: %s\n", lf->fname);
143 
144    of = lf->next;
145    if (lf->bpipe) {
146       close_bpipe(lf->bpipe);
147       lf->bpipe = NULL;
148    } else if (lf->fd) {
149       fclose(lf->fd);
150    }
151    Dmsg1(dbglvl, "Close cfg file %s\n", lf->fname);
152    if (lf->fname) {
153       free(lf->fname);
154    }
155    free_memory(lf->line);
156    lf->line = NULL;
157    free_memory(lf->str);
158    lf->str = NULL;
159    if (of) {
160       of->options = lf->options;      /* preserve options */
161       memcpy(lf, of, sizeof(LEX));
162       Dmsg1(dbglvl, "Restart scan of cfg file %s\n", of->fname);
163    } else {
164       of = lf;
165       lf = NULL;
166    }
167    if (of) {
168       free(of);
169    }
170    return lf;
171 }
172 
173 /*
174  * Open a configuration in memory buffer. We push the
175  * state of the current file (lf) so that we
176  * can do includes.  This is a bit of a hammer.
177  * Instead of passing back the pointer to the
178  * new packet, I simply replace the contents
179  * of the caller's packet with the new packet,
180  * and link the contents of the old packet into
181  * the next field.
182  *
183  */
lex_open_buf(LEX * lf,const char * buffer,LEX_ERROR_HANDLER * scan_error)184 LEX *lex_open_buf(LEX *lf, const char *buffer, LEX_ERROR_HANDLER *scan_error)
185 
186 {
187    LEX *nf;
188 
189    Dmsg0(400, "Open config buffer\n");
190    nf = (LEX *)malloc(sizeof(LEX));
191    if (lf) {
192       memcpy(nf, lf, sizeof(LEX));
193       memset(lf, 0, sizeof(LEX));
194       lf->next = nf;                  /* if have lf, push it behind new one */
195       lf->options = nf->options;      /* preserve user options */
196       /*
197        * preserve err_type to prevent bacula exiting on 'reload'
198        * if config is invalid. Fixes bug #877
199        */
200       lf->err_type = nf->err_type;
201    } else {
202       lf = nf;                        /* start new packet */
203       memset(lf, 0, sizeof(LEX));
204       lex_set_error_handler_error_type(lf, M_ERROR_TERM);
205    }
206    if (scan_error) {
207       lf->scan_error = scan_error;
208    } else {
209       lex_set_default_error_handler(lf);
210    }
211    lf->fd = NULL;
212    lf->bpipe = NULL;
213    lf->fname = NULL;
214    lf->line = get_memory(5000);
215    pm_strcpy(lf->line, buffer);
216    pm_strcat(lf->line, "");
217    lf->state = lex_none;
218    lf->ch = 0;
219    lf->str = get_memory(5000);
220    return lf;
221 }
222 
223 /*
224  * Open a new configuration file. We push the
225  * state of the current file (lf) so that we
226  * can do includes.  This is a bit of a hammer.
227  * Instead of passing back the pointer to the
228  * new packet, I simply replace the contents
229  * of the caller's packet with the new packet,
230  * and link the contents of the old packet into
231  * the next field.
232  *
233  */
lex_open_file(LEX * lf,const char * filename,LEX_ERROR_HANDLER * scan_error)234 LEX *lex_open_file(LEX *lf, const char *filename, LEX_ERROR_HANDLER *scan_error)
235 
236 {
237    LEX *nf;
238    FILE *fd;
239    BPIPE *bpipe = NULL;
240    char *fname = bstrdup(filename);
241 
242    if (fname[0] == '|') {
243       if ((bpipe = open_bpipe(fname+1, 0, "reb")) == NULL) {
244          free(fname);
245          return NULL;
246       }
247       close_epipe(bpipe);       /* discard stderr messages */
248       fd = bpipe->rfd;
249    } else if ((fd = fopen(fname, "rb")) == NULL) {
250       free(fname);
251       return NULL;
252    }
253    Dmsg1(400, "Open config file: %s\n", fname);
254    nf = (LEX *)malloc(sizeof(LEX));
255    if (lf) {
256       memcpy(nf, lf, sizeof(LEX));
257       memset(lf, 0, sizeof(LEX));
258       lf->next = nf;                  /* if have lf, push it behind new one */
259       lf->options = nf->options;      /* preserve user options */
260       /*
261        * preserve err_type to prevent bacula exiting on 'reload'
262        * if config is invalid. Fixes bug #877
263        */
264       lf->err_type = nf->err_type;
265    } else {
266       lf = nf;                        /* start new packet */
267       memset(lf, 0, sizeof(LEX));
268       lex_set_error_handler_error_type(lf, M_ERROR_TERM);
269    }
270    if (scan_error) {
271       lf->scan_error = scan_error;
272    } else {
273       lex_set_default_error_handler(lf);
274    }
275    lf->fd = fd;
276    lf->bpipe = bpipe;
277    lf->fname = fname;
278    lf->line = get_memory(5000);
279    lf->state = lex_none;
280    lf->ch = L_EOL;
281    lf->str = get_memory(5000);
282    Dmsg1(dbglvl, "Return lex=%x\n", lf);
283    return lf;
284 }
285 
286 /*
287  * Get the next character from the input.
288  *  Returns the character or
289  *    L_EOF if end of file
290  *    L_EOL if end of line
291  */
lex_get_char(LEX * lf)292 int lex_get_char(LEX *lf)
293 {
294    if (lf->ch == L_EOF) {
295       Emsg0(M_ABORT, 0, _("get_char: called after EOF."
296          " You may have a open double quote without the closing double quote.\n"));
297    }
298    if (lf->fd && lf->ch == L_EOL) {
299       if (bfgets(lf->line, lf->fd) == NULL) {
300          lf->ch = L_EOF;
301          if (lf->next) {
302             lex_close_file(lf);
303          }
304          return lf->ch;
305       }
306       lf->line_no++;
307       lf->col_no = 0;
308       Dmsg2(1000, "fget line=%d %s", lf->line_no, lf->line);
309    } else if (lf->ch == L_EOL) {
310       lf->line_no++;
311       lf->col_no++;
312    }
313    lf->ch = (uint8_t)lf->line[lf->col_no];
314    if (lf->fd) {
315       if (lf->ch == 0) {
316          lf->ch = L_EOL;           /* reached end of line, force bfgets */
317       } else {
318          lf->col_no++;
319       }
320    } else {
321       if (lf->ch == 0) {           /* End of buffer, stop scan */
322          lf->ch = L_EOF;
323          if (lf->next) {
324             lex_close_file(lf);
325          }
326          return lf->ch;
327       } else if (lf->ch == '\n') {  /* End of line */
328          Dmsg0(dbglvl, "Found newline return L_EOL\n");
329          lf->ch = L_EOL;
330       } else {
331          lf->col_no++;
332       }
333    }
334    Dmsg3(dbglvl, "lex_get_char: %c %d col=%d\n", lf->ch, lf->ch, lf->col_no);
335    return lf->ch;
336 }
337 
lex_unget_char(LEX * lf)338 void lex_unget_char(LEX *lf)
339 {
340    if (lf->ch == L_EOL) {
341       lf->ch = 0;                     /* End of line, force read of next one */
342    } else {
343       lf->col_no--;                   /* Backup to re-read char */
344    }
345 }
346 
347 
348 /*
349  * Add a character to the current string
350  */
add_str(LEX * lf,int ch)351 static void add_str(LEX *lf, int ch)
352 {
353    if (lf->str_len >= sizeof_pool_memory(lf->str)) {
354       Emsg3(M_ERROR_TERM, 0, _(
355            _("Config token too long, file: %s, line %d, begins at line %d\n")),
356              lf->fname, lf->line_no, lf->begin_line_no);
357    }
358    lf->str[lf->str_len++] = ch;
359    lf->str[lf->str_len] = 0;
360 }
361 
362 /*
363  * Begin the string
364  */
begin_str(LEX * lf,int ch)365 static void begin_str(LEX *lf, int ch)
366 {
367    lf->str_len = 0;
368    lf->str[0] = 0;
369    if (ch != 0) {
370       add_str(lf, ch);
371    }
372    lf->begin_line_no = lf->line_no;   /* save start string line no */
373 }
374 
375 #ifdef DEBUG
lex_state_to_str(int state)376 static const char *lex_state_to_str(int state)
377 {
378    switch (state) {
379    case lex_none:          return _("none");
380    case lex_comment:       return _("comment");
381    case lex_number:        return _("number");
382    case lex_ip_addr:       return _("ip_addr");
383    case lex_identifier:    return _("identifier");
384    case lex_string:        return _("string");
385    case lex_quoted_string: return _("quoted_string");
386    case lex_include:       return _("include");
387    case lex_include_quoted_string: return _("include_quoted_string");
388    case lex_utf8_bom:      return _("UTF-8 Byte Order Mark");
389    case lex_utf16_le_bom:  return _("UTF-16le Byte Order Mark");
390    default:                return "??????";
391    }
392 }
393 #endif
394 
395 /*
396  * Convert a lex token to a string
397  * used for debug/error printing.
398  */
lex_tok_to_str(int token)399 const char *lex_tok_to_str(int token)
400 {
401    switch(token) {
402    case L_EOF:             return "L_EOF";
403    case L_EOL:             return "L_EOL";
404    case T_NONE:            return "T_NONE";
405    case T_NUMBER:          return "T_NUMBER";
406    case T_IPADDR:          return "T_IPADDR";
407    case T_IDENTIFIER:      return "T_IDENTIFIER";
408    case T_UNQUOTED_STRING: return "T_UNQUOTED_STRING";
409    case T_QUOTED_STRING:   return "T_QUOTED_STRING";
410    case T_BOB:             return "T_BOB";
411    case T_EOB:             return "T_EOB";
412    case T_EQUALS:          return "T_EQUALS";
413    case T_ERROR:           return "T_ERROR";
414    case T_EOF:             return "T_EOF";
415    case T_COMMA:           return "T_COMMA";
416    case T_EOL:             return "T_EOL";
417    case T_UTF8_BOM:        return "T_UTF8_BOM";
418    case T_UTF16_BOM:       return "T_UTF16_BOM";
419    default:                return "??????";
420    }
421 }
422 
scan_pint(LEX * lf,char * str)423 static uint32_t scan_pint(LEX *lf, char *str)
424 {
425    int64_t val = 0;
426    if (!is_a_number(str)) {
427       scan_err1(lf, _("expected a positive integer number, got: %s"), str);
428       /* NOT REACHED */
429    } else {
430       errno = 0;
431       val = str_to_int64(str);
432       if (errno != 0 || val < 0) {
433          scan_err1(lf, _("expected a positive integer number, got: %s"), str);
434          /* NOT REACHED */
435       }
436    }
437    return (uint32_t)val;
438 }
439 
scan_pint64(LEX * lf,char * str)440 static uint64_t scan_pint64(LEX *lf, char *str)
441 {
442    uint64_t val = 0;
443    if (!is_a_number(str)) {
444       scan_err1(lf, _("expected a positive integer number, got: %s"), str);
445       /* NOT REACHED */
446    } else {
447       errno = 0;
448       val = str_to_uint64(str);
449       if (errno != 0) {
450          scan_err1(lf, _("expected a positive integer number, got: %s"), str);
451          /* NOT REACHED */
452       }
453    }
454    return val;
455 }
456 
457 /*
458  *
459  * Get the next token from the input
460  *
461  */
462 int
lex_get_token(LEX * lf,int expect)463 lex_get_token(LEX *lf, int expect)
464 {
465    int ch, nch;
466    int token = T_NONE;
467    bool esc_next = false;
468    /* Unicode files, especially on Win32, may begin with a "Byte Order Mark"
469       to indicate which transmission format the file is in. The codepoint for
470       this mark is U+FEFF and is represented as the octets EF-BB-BF in UTF-8
471       and as FF-FE in UTF-16le(little endian) and  FE-FF in UTF-16(big endian).
472       We use a distinct state for UTF-8 and UTF-16le, and use bom_bytes_seen
473       to tell which byte we are expecting. */
474    int bom_bytes_seen = 0;
475 
476    Dmsg1(dbglvl, "enter lex_get_token state=%s\n", lex_state_to_str(lf->state));
477    while (token == T_NONE) {
478       ch = lex_get_char(lf);
479       switch (lf->state) {
480       case lex_none:
481          Dmsg2(dbglvl, "Lex state lex_none ch=%c,%d\n", ch, ch);
482          if (B_ISSPACE(ch))
483             break;
484          if (B_ISALPHA(ch)) {
485             if (lf->options & LOPT_NO_IDENT || lf->options & LOPT_STRING) {
486                lf->state = lex_string;
487             } else {
488                lf->state = lex_identifier;
489             }
490             begin_str(lf, ch);
491             break;
492          }
493          if (B_ISDIGIT(ch)) {
494             if (lf->options & LOPT_STRING) {
495                lf->state = lex_string;
496             } else {
497                lf->state = lex_number;
498             }
499             begin_str(lf, ch);
500             break;
501          }
502          Dmsg0(dbglvl, "Enter lex_none switch\n");
503          switch (ch) {
504          case L_EOF:
505             token = T_EOF;
506             Dmsg0(dbglvl, "got L_EOF set token=T_EOF\n");
507             break;
508          case '\\':
509             nch = lex_get_char(lf);
510             if (nch == ' ' || nch == '\n' || nch == '\r' || nch == L_EOL) {
511                lf->ch = L_EOL;        /* force end of line */
512             }
513             break;
514          case '#':
515             lf->state = lex_comment;
516             break;
517          case '{':
518             token = T_BOB;
519             begin_str(lf, ch);
520             break;
521          case '}':
522             token = T_EOB;
523             begin_str(lf, ch);
524             break;
525          case '"':
526             lf->state = lex_quoted_string;
527             begin_str(lf, 0);
528             break;
529          case '=':
530             token = T_EQUALS;
531             begin_str(lf, ch);
532             break;
533          case ',':
534             token = T_COMMA;
535             begin_str(lf, ch);
536             break;
537          case ';':
538             if (expect != T_SKIP_EOL) {
539                token = T_EOL;      /* treat ; like EOL */
540             }
541             break;
542          case L_EOL:
543             Dmsg0(dbglvl, "got L_EOL set token=T_EOL\n");
544             if (expect != T_SKIP_EOL) {
545                token = T_EOL;
546             }
547             break;
548          case '@':
549             /* In NO_EXTERN mode, @ is part of a string */
550             if (lf->options & LOPT_NO_EXTERN) {
551                lf->state = lex_string;
552                begin_str(lf, ch);
553             } else {
554                lf->state = lex_include;
555                begin_str(lf, 0);
556             }
557             break;
558          case 0xEF: /* probably a UTF-8 BOM */
559          case 0xFF: /* probably a UTF-16le BOM */
560          case 0xFE: /* probably a UTF-16be BOM (error)*/
561             if (lf->line_no != 1 || lf->col_no != 1)
562             {
563                lf->state = lex_string;
564                begin_str(lf, ch);
565             } else {
566                bom_bytes_seen = 1;
567                if (ch == 0xEF) {
568                   lf->state = lex_utf8_bom;
569                } else if (ch == 0xFF) {
570                   lf->state = lex_utf16_le_bom;
571                } else {
572                   scan_err0(lf, _("This config file appears to be in an "
573                      "unsupported Unicode format (UTF-16be). Please resave as UTF-8\n"));
574                   return T_ERROR;
575                }
576             }
577             break;
578          default:
579             lf->state = lex_string;
580             begin_str(lf, ch);
581             break;
582          }
583          break;
584       case lex_comment:
585          Dmsg1(dbglvl, "Lex state lex_comment ch=%x\n", ch);
586          if (ch == L_EOL) {
587             lf->state = lex_none;
588             if (expect != T_SKIP_EOL) {
589                token = T_EOL;
590             }
591          } else if (ch == L_EOF) {
592             token = T_ERROR;
593          }
594          break;
595       case lex_number:
596          Dmsg2(dbglvl, "Lex state lex_number ch=%x %c\n", ch, ch);
597          if (ch == L_EOF) {
598             token = T_ERROR;
599             break;
600          }
601          /* Might want to allow trailing specifications here */
602          if (B_ISDIGIT(ch)) {
603             add_str(lf, ch);
604             break;
605          }
606 
607          /* A valid number can be terminated by the following */
608          if (B_ISSPACE(ch) || ch == L_EOL || ch == ',' || ch == ';') {
609             token = T_NUMBER;
610             lf->state = lex_none;
611          } else {
612             lf->state = lex_string;
613          }
614          lex_unget_char(lf);
615          break;
616       case lex_ip_addr:
617          if (ch == L_EOF) {
618             token = T_ERROR;
619             break;
620          }
621          Dmsg1(dbglvl, "Lex state lex_ip_addr ch=%x\n", ch);
622          break;
623       case lex_string:
624          Dmsg1(dbglvl, "Lex state lex_string ch=%x\n", ch);
625          if (ch == L_EOF) {
626             token = T_ERROR;
627             break;
628          }
629          if (ch == '\n' || ch == L_EOL || ch == '=' || ch == '}' || ch == '{' ||
630              ch == '\r' || ch == ';' || ch == ',' || ch == '#' || (B_ISSPACE(ch)) ) {
631             lex_unget_char(lf);
632             token = T_UNQUOTED_STRING;
633             lf->state = lex_none;
634             break;
635          }
636          add_str(lf, ch);
637          break;
638       case lex_identifier:
639          Dmsg2(dbglvl, "Lex state lex_identifier ch=%x %c\n", ch, ch);
640          if (B_ISALPHA(ch)) {
641             add_str(lf, ch);
642             break;
643          } else if (B_ISSPACE(ch)) {
644             break;
645          } else if (ch == '\n' || ch == L_EOL || ch == '=' || ch == '}' || ch == '{' ||
646                     ch == '\r' || ch == ';' || ch == ','   || ch == '"' || ch == '#') {
647             lex_unget_char(lf);
648             token = T_IDENTIFIER;
649             lf->state = lex_none;
650             break;
651          } else if (ch == L_EOF) {
652             token = T_ERROR;
653             lf->state = lex_none;
654             begin_str(lf, ch);
655             break;
656          }
657          /* Some non-alpha character => string */
658          lf->state = lex_string;
659          add_str(lf, ch);
660          break;
661       case lex_quoted_string:
662          Dmsg2(dbglvl, "Lex state lex_quoted_string ch=%x %c\n", ch, ch);
663          if (ch == L_EOF) {
664             token = T_ERROR;
665             break;
666          }
667          if (ch == L_EOL) {
668             esc_next = false;
669             break;
670          }
671          if (esc_next) {
672             add_str(lf, ch);
673             esc_next = false;
674             break;
675          }
676          if (ch == '\\') {
677             esc_next = true;
678             break;
679          }
680          if (ch == '"') {
681             token = T_QUOTED_STRING;
682             /*
683              * Since we may be scanning a quoted list of names,
684              *  we get the next character (a comma indicates another
685              *  one), then we put it back for rescanning.
686              */
687             lex_get_char(lf);
688             lex_unget_char(lf);
689             lf->state = lex_none;
690             break;
691          }
692          add_str(lf, ch);
693          break;
694       case lex_include_quoted_string:
695          if (ch == L_EOF) {
696             token = T_ERROR;
697             break;
698          }
699          if (esc_next) {
700             add_str(lf, ch);
701             esc_next = false;
702             break;
703          }
704          if (ch == '\\') {
705             esc_next = true;
706             break;
707          }
708          if (ch == '"') {
709             /* Keep the original LEX so we can print an error if the included file can't be opened. */
710             LEX* lfori = lf;
711             /* Skip the double quote when restarting parsing */
712             lex_get_char(lf);
713 
714             lf->state = lex_none;
715             lf = lex_open_file(lf, lf->str, lf->scan_error);
716             if (lf == NULL) {
717                berrno be;
718                scan_err2(lfori, _("Cannot open included config file %s: %s\n"),
719                   lfori->str, be.bstrerror());
720                return T_ERROR;
721             }
722             break;
723          }
724          add_str(lf, ch);
725          break;
726       case lex_include:            /* scanning a filename */
727          if (ch == L_EOF) {
728             token = T_ERROR;
729             break;
730          }
731          if (ch == '"') {
732             lf->state = lex_include_quoted_string;
733             break;
734          }
735 
736 
737          if (B_ISSPACE(ch) || ch == '\n' || ch == L_EOL || ch == '}' || ch == '{' ||
738              ch == ';' || ch == ','   || ch == '"' || ch == '#') {
739             /* Keep the original LEX so we can print an error if the included file can't be opened. */
740             LEX* lfori = lf;
741 
742             lf->state = lex_none;
743             lf = lex_open_file(lf, lf->str, lf->scan_error);
744             if (lf == NULL) {
745                berrno be;
746                scan_err2(lfori, _("Cannot open included config file %s: %s\n"),
747                   lfori->str, be.bstrerror());
748                return T_ERROR;
749             }
750             break;
751          }
752          add_str(lf, ch);
753          break;
754       case lex_utf8_bom:
755          /* we only end up in this state if we have read an 0xEF
756             as the first byte of the file, indicating we are probably
757             reading a UTF-8 file */
758          if (ch == 0xBB && bom_bytes_seen == 1) {
759             bom_bytes_seen++;
760          } else if (ch == 0xBF && bom_bytes_seen == 2) {
761             token = T_UTF8_BOM;
762             lf->state = lex_none;
763          } else {
764             token = T_ERROR;
765          }
766          break;
767       case lex_utf16_le_bom:
768          /* we only end up in this state if we have read an 0xFF
769             as the first byte of the file -- indicating that we are
770             probably dealing with an Intel based (little endian) UTF-16 file*/
771          if (ch == 0xFE) {
772             token = T_UTF16_BOM;
773             lf->state = lex_none;
774          } else {
775             token = T_ERROR;
776          }
777          break;
778       }
779       Dmsg4(dbglvl, "ch=%d state=%s token=%s %c\n", ch, lex_state_to_str(lf->state),
780         lex_tok_to_str(token), ch);
781    }
782    Dmsg2(dbglvl, "lex returning: line %d token: %s\n", lf->line_no, lex_tok_to_str(token));
783    lf->token = token;
784 
785    /*
786     * Here is where we check to see if the user has set certain
787     *  expectations (e.g. 32 bit integer). If so, we do type checking
788     *  and possible additional scanning (e.g. for range).
789     */
790    switch (expect) {
791    case T_PINT32:
792       lf->pint32_val = scan_pint(lf, lf->str);
793       lf->pint32_val2 = lf->pint32_val;
794       token = T_PINT32;
795       break;
796 
797    case T_PINT32_RANGE:
798       if (token == T_NUMBER) {
799          lf->pint32_val = scan_pint(lf, lf->str);
800          lf->pint32_val2 = lf->pint32_val;
801          token = T_PINT32;
802       } else {
803          char *p = strchr(lf->str, '-');
804          if (!p) {
805             scan_err2(lf, _("expected an integer or a range, got %s: %s"),
806                lex_tok_to_str(token), lf->str);
807             token = T_ERROR;
808             break;
809          }
810          *p++ = 0;                       /* terminate first half of range */
811          lf->pint32_val  = scan_pint(lf, lf->str);
812          lf->pint32_val2 = scan_pint(lf, p);
813          token = T_PINT32_RANGE;
814       }
815       break;
816 
817    case T_INT32:
818       if (token != T_NUMBER || !is_a_number(lf->str)) {
819          scan_err2(lf, _("expected an integer number, got %s: %s"),
820                lex_tok_to_str(token), lf->str);
821          token = T_ERROR;
822          break;
823       }
824       errno = 0;
825       lf->int32_val = (int32_t)str_to_int64(lf->str);
826       if (errno != 0) {
827          scan_err2(lf, _("expected an integer number, got %s: %s"),
828                lex_tok_to_str(token), lf->str);
829          token = T_ERROR;
830       } else {
831          token = T_INT32;
832       }
833       break;
834 
835    case T_INT64:
836       Dmsg2(dbglvl, "int64=:%s: %f\n", lf->str, strtod(lf->str, NULL));
837       if (token != T_NUMBER || !is_a_number(lf->str)) {
838          scan_err2(lf, _("expected an integer number, got %s: %s"),
839                lex_tok_to_str(token), lf->str);
840          token = T_ERROR;
841          break;
842       }
843       errno = 0;
844       lf->int64_val = str_to_int64(lf->str);
845       if (errno != 0) {
846          scan_err2(lf, _("expected an integer number, got %s: %s"),
847                lex_tok_to_str(token), lf->str);
848          token = T_ERROR;
849       } else {
850          token = T_INT64;
851       }
852       break;
853 
854    case T_PINT64_RANGE:
855       if (token == T_NUMBER) {
856          lf->pint64_val = scan_pint64(lf, lf->str);
857          lf->pint64_val2 = lf->pint64_val;
858          token = T_PINT64;
859       } else {
860          char *p = strchr(lf->str, '-');
861          if (!p) {
862             scan_err2(lf, _("expected an integer or a range, got %s: %s"),
863                lex_tok_to_str(token), lf->str);
864             token = T_ERROR;
865             break;
866          }
867          *p++ = 0;                       /* terminate first half of range */
868          lf->pint64_val  = scan_pint64(lf, lf->str);
869          lf->pint64_val2 = scan_pint64(lf, p);
870          token = T_PINT64_RANGE;
871       }
872       break;
873 
874    case T_NAME:
875       if (token != T_IDENTIFIER && token != T_UNQUOTED_STRING && token != T_QUOTED_STRING) {
876          scan_err2(lf, _("expected a name, got %s: %s"),
877                lex_tok_to_str(token), lf->str);
878          token = T_ERROR;
879       } else if (lf->str_len > MAX_RES_NAME_LENGTH) {
880          scan_err3(lf, _("name %s length %d too long, max is %d\n"), lf->str,
881             lf->str_len, MAX_RES_NAME_LENGTH);
882          token = T_ERROR;
883       }
884       break;
885 
886    case T_STRING:
887       if (token != T_IDENTIFIER && token != T_UNQUOTED_STRING && token != T_QUOTED_STRING) {
888          scan_err2(lf, _("expected a string, got %s: %s"),
889                lex_tok_to_str(token), lf->str);
890          token = T_ERROR;
891       } else {
892          token = T_STRING;
893       }
894       break;
895 
896 
897    default:
898       break;                          /* no expectation given */
899    }
900    lf->token = token;                 /* set possible new token */
901    return token;
902 }
903