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  *   Master Configuration routines.
21  *
22  *   This file contains the common parts of the Bacula
23  *   configuration routines.
24  *
25  *   Note, the configuration file parser consists of three parts
26  *
27  *   1. The generic lexical scanner in lib/lex.c and lib/lex.h
28  *
29  *   2. The generic config  scanner in lib/parse_conf.c and
30  *      lib/parse_conf.h.
31  *      These files contain the parser code, some utility
32  *      routines, and the common store routines (name, int,
33  *      string, time, int64, size, ...).
34  *
35  *   3. The daemon specific file, which contains the Resource
36  *      definitions as well as any specific store routines
37  *      for the resource records.
38  *
39  *    N.B. This is a two pass parser, so if you malloc() a string
40  *         in a "store" routine, you must ensure to do it during
41  *         only one of the two passes, or to free it between.
42  *         Also, note that the resource record is malloced and
43  *         saved in save_resource() during pass 1.  Anything that
44  *         you want saved after pass two (e.g. resource pointers)
45  *         must explicitly be done in save_resource. Take a look
46  *         at the Job resource in src/dird/dird_conf.c to see how
47  *         it is done.
48  *
49  *     Kern Sibbald, January MM
50  *
51  */
52 
53 
54 #include "bacula.h"
55 
56 #if defined(HAVE_WIN32)
57 #include "shlobj.h"
58 #else
59 #define MAX_PATH  1024
60 #endif
61 
62 /*
63  * Define the Union of all the common resource structure definitions.
64  */
65 union URES {
66    MSGS  res_msgs;
67    RES hdr;
68    COLLECTOR  res_collector;
69 };
70 
71 #if defined(_MSC_VER)
72 // work around visual studio name mangling preventing external linkage since res_all
73 // is declared as a different type when instantiated.
74 extern "C" URES res_all;
75 #else
76 extern  URES res_all;
77 #endif
78 
79 extern brwlock_t res_lock;            /* resource lock */
80 
81 
82 /* Forward referenced subroutines */
83 static void scan_types(LEX *lc, MSGS *msg, int dest, char *where, char *cmd);
84 static const char *get_default_configdir();
85 
86 /* Common Resource definitions */
87 
88 /*
89  * Message resource directives
90  * Note: keep all store_mesgs last in the list as they are all
91  *   output in json as a list.
92  *   Also, the list store_msgs item must have flags set to ITEM_LAST
93  *   so that the list editor (bjson.c) knows when to stop.
94  *
95  *  name         handler      value       code   flags  default_value
96  */
97 RES_ITEM msgs_items[] = {
98    {"Name",        store_name,    ITEM(res_msgs.hdr.name),  0, ITEM_REQUIRED, 0},
99    {"Description", store_str,     ITEM(res_msgs.hdr.desc),  0, 0, 0},
100    {"MailCommand", store_str,     ITEM(res_msgs.mail_cmd),  0, ITEM_ALLOW_DUPS, 0},
101    {"OperatorCommand", store_str, ITEM(res_msgs.operator_cmd), 0, ITEM_ALLOW_DUPS, 0},
102    /* See comments above */
103    {"Syslog",      store_msgs, ITEM(res_msgs), MD_SYSLOG,   0, 0},
104    {"Mail",        store_msgs, ITEM(res_msgs), MD_MAIL,     0, 0},
105    {"MailOnError", store_msgs, ITEM(res_msgs), MD_MAIL_ON_ERROR, 0, 0},
106    {"MailOnSuccess", store_msgs, ITEM(res_msgs), MD_MAIL_ON_SUCCESS, 0, 0},
107    {"File",        store_msgs, ITEM(res_msgs), MD_FILE,     0, 0},
108    {"Append",      store_msgs, ITEM(res_msgs), MD_APPEND,   0, 0},
109    {"Stdout",      store_msgs, ITEM(res_msgs), MD_STDOUT,   0, 0},
110    {"Stderr",      store_msgs, ITEM(res_msgs), MD_STDERR,   0, 0},
111    {"Director",    store_msgs, ITEM(res_msgs), MD_DIRECTOR, 0, 0},
112    {"Console",     store_msgs, ITEM(res_msgs), MD_CONSOLE,  0, 0},
113    {"Operator",    store_msgs, ITEM(res_msgs), MD_OPERATOR, 0, 0},
114    {"Catalog",     store_msgs, ITEM(res_msgs), MD_CATALOG,  ITEM_LAST, 0},
115    {NULL,          NULL,       {0},       0, 0, 0}
116 };
117 
118 /*
119  * Statistics resource directives
120  *
121  *  name         handler      value       code   flags  default_value
122  */
123 RES_ITEM collector_items[] = {
124    {"Name",             store_name,       ITEM(res_collector.hdr.name),          0, ITEM_REQUIRED, 0},
125    {"Description",      store_str,        ITEM(res_collector.hdr.desc),          0, 0, 0},
126    {"Prefix",           store_str,        ITEM(res_collector.prefix),            0, 0, 0},
127    {"Metrics",          store_alist_str,  ITEM(res_collector.metrics),           0, 0, 0},   /* default all */
128    {"Interval",         store_time,       ITEM(res_collector.interval),          0, ITEM_DEFAULT, 5*60}, /* default 5 min */
129    {"Port",             store_pint32,     ITEM(res_collector.port),              0, 0, 0},
130    {"Host",             store_str,        ITEM(res_collector.host),              0, 0, 0},
131    {"Type",             store_coll_type,  ITEM(res_collector.type),              0, ITEM_REQUIRED, 0},
132    {"File",             store_str,        ITEM(res_collector.file),              0, 0, 0},
133    {"MangleMetric",     store_bool,       ITEM(res_collector.mangle_name),       0, 0, 0},
134    {NULL,               NULL,             {0},                                   0, 0, 0}
135 };
136 
137 /* Various message types */
138 s_kw msg_types[] = {
139    {"Debug",         M_DEBUG},  /* Keep 1st place */
140    {"Saved",         M_SAVED},  /* Keep 2nd place */
141    {"Events",        M_EVENTS}, /* Keep 3rd place */
142    {"Abort",         M_ABORT},
143    {"Fatal",         M_FATAL},
144    {"Error",         M_ERROR},
145    {"Warning",       M_WARNING},
146    {"Info",          M_INFO},
147    {"NotSaved",      M_NOTSAVED},
148    {"Skipped",       M_SKIPPED},
149    {"Mount",         M_MOUNT},
150    {"Terminate",     M_TERM},
151    {"Restored",      M_RESTORED},
152    {"Security",      M_SECURITY},
153    {"Alert",         M_ALERT},
154    {"VolMgmt",       M_VOLMGMT},
155    {"ErrorTerm",     M_ERROR_TERM},
156    {"All",           M_MAX+1},
157    {NULL,            0}
158 };
159 
160 
161 /*
162  * Tape Label types permitted in Pool records
163  *
164  *   tape label      label code = token
165  */
166 s_kw tapelabels[] = {
167    {"Bacula",        B_BACULA_LABEL},
168    {"ANSI",          B_ANSI_LABEL},
169    {"IBM",           B_IBM_LABEL},
170    {NULL,            0}
171 };
172 
173 /*
174  * Keywords (RHS) permitted in Statistics type records
175  *
176  *   type_name       backend_type
177  */
178 s_collt collectortypes[] = {
179    {"CSV",           COLLECTOR_BACKEND_CSV},
180    {"Graphite",      COLLECTOR_BACKEND_Graphite},
181    {NULL,            0}
182 };
183 
184 
185 /* Simply print a message */
prtmsg(void * sock,const char * fmt,...)186 static void prtmsg(void *sock, const char *fmt, ...)
187 {
188    va_list arg_ptr;
189 
190    va_start(arg_ptr, fmt);
191    vfprintf(stdout, fmt, arg_ptr);
192    va_end(arg_ptr);
193 }
194 
res_to_str(int rcode)195 const char *res_to_str(int rcode)
196 {
197    if (rcode < r_first || rcode > r_last) {
198       return _("***UNKNOWN***");
199    } else {
200       return resources[rcode-r_first].name;
201    }
202 }
203 
204 /*
205  * Create a new res_head pointer to a list of res_heads
206  */
init_res_head(RES_HEAD *** rhead,int32_t rfirst,int32_t rlast)207 void CONFIG::init_res_head(RES_HEAD ***rhead, int32_t rfirst, int32_t rlast)
208 {
209    int num = rlast - rfirst + 1;
210    RES *res = NULL;
211    RES_HEAD **rh;
212    rh = *rhead = (RES_HEAD **)malloc(num * sizeof(RES_HEAD));
213    for (int i=0; i<num; i++) {
214       rh[i] = (RES_HEAD *)malloc(sizeof(RES_HEAD));
215       rh[i]->res_list = New(rblist(res, &res->link));
216       rh[i]->first = NULL;
217       rh[i]->last = NULL;
218    }
219 }
220 
221 /*
222  * Copy the resource in res_all into a new allocated resource
223  * an insert it into the resource list.
224  */
insert_res(int rindex,int size)225 bool CONFIG::insert_res(int rindex, int size)
226 {
227    RES *res = (RES *)malloc(size);
228    memcpy(res, m_res_all, size);
229    return insert_res(rindex, res);
230 }
231 
232 /*
233  * Insert the resource res into the resource list.
234  */
insert_res(int rindex,RES * res)235 bool CONFIG::insert_res(int rindex, RES *res)
236 {
237    rblist *list = m_res_head[rindex]->res_list;
238    if (list->empty()) {
239       list->insert(res, res_compare);
240       m_res_head[rindex]->first = res;
241       m_res_head[rindex]->last = res;
242    } else {
243       RES *item, *prev;
244       prev = m_res_head[rindex]->last;
245       item = (RES *)list->insert(res, res_compare);
246       if (item != res) {
247          Mmsg(m_errmsg, _("Attempt to define second \"%s\" resource named \"%s\" is not permitted.\n"),
248               resources[rindex].name, ((URES *)res)->hdr.name);
249          return false;
250       }
251       prev->res_next = res;
252       m_res_head[rindex]->last = res;
253    }
254    Dmsg2(900, _("Inserted res: %s index=%d\n"), ((URES *)res)->hdr.name, rindex);
255    return true;
256 }
257 
258 /*
259  * Initialize the static structure to zeros, then
260  *  apply all the default values.
261  */
init_resource0(CONFIG * config,int type,RES_ITEM * items,int pass)262 void init_resource0(CONFIG *config, int type, RES_ITEM *items, int pass)
263 {
264    int i;
265    int rindex = type - r_first;
266 
267    memset(config->m_res_all, 0, config->m_res_all_size);
268    res_all.hdr.rcode = type;
269    res_all.hdr.refcnt = 1;
270 
271    /* Set defaults in each item */
272    for (i=0; items[i].name; i++) {
273       Dmsg3(900, "Item=%s def=%s defval=%d\n", items[i].name,
274             (items[i].flags & ITEM_DEFAULT) ? "yes" : "no",
275             items[i].default_value);
276       if (items[i].flags & ITEM_DEFAULT && items[i].default_value != 0) {
277          if (items[i].handler == store_bit) {
278             *(uint32_t *)(items[i].value) |= items[i].code;
279          } else if (items[i].handler == store_bool) {
280             *(bool *)(items[i].value) = items[i].default_value != 0;
281          } else if (items[i].handler == store_pint32 ||
282                     items[i].handler == store_int32 ||
283                     items[i].handler == store_size32) {
284             *(uint32_t *)(items[i].value) = items[i].default_value;
285          } else if (items[i].handler == store_int64) {
286             *(int64_t *)(items[i].value) = items[i].default_value;
287          } else if (items[i].handler == store_size64) {
288             *(uint64_t *)(items[i].value) = (uint64_t)items[i].default_value;
289          } else if (items[i].handler == store_speed) {
290             *(uint64_t *)(items[i].value) = (uint64_t)items[i].default_value;
291          } else if (items[i].handler == store_time) {
292             *(utime_t *)(items[i].value) = (utime_t)items[i].default_value;
293          } else if (pass == 1 && items[i].handler == store_addresses) {
294             init_default_addresses((dlist**)items[i].value, items[i].default_value);
295          }
296       }
297       /* If this triggers, take a look at lib/parse_conf.h */
298       if (i >= MAX_RES_ITEMS) {
299          Emsg1(M_ERROR_TERM, 0, _("Too many directives in \"%s\" resource\n"), resources[rindex].name);
300       }
301    }
302 }
303 
304 /* Initialize a resouce with default values */
init_resource(CONFIG * config,uint32_t type,void * res,int size)305 bool init_resource(CONFIG *config, uint32_t type, void *res, int size)
306 {
307    RES_ITEM *items;
308    for (int i=0; resources[i].name; i++) {
309       if (resources[i].rcode == type) {
310          items = resources[i].items;
311          if (!items) {
312             return false;
313          }
314          init_resource0(config, type, items, 1);
315          memcpy(res, config->m_res_all, size);
316          return true;
317       }
318    }
319    return false;
320 }
321 
322 /*
323  * Dump each resource of type
324  */
dump_each_resource(int type,void sendit (void * sock,const char * fmt,...),void * sock)325 void dump_each_resource(int type, void sendit(void *sock, const char *fmt, ...), void *sock)
326 {
327    RES *res = NULL;
328 
329    if (type < 0) {                    /* no recursion */
330       type = -type;
331    }
332    foreach_res(res, type) {
333       dump_resource(-type, res, sendit, sock);
334    }
335 }
336 
337 
338 /* Store Messages Destination information */
store_msgs(LEX * lc,RES_ITEM * item,int index,int pass)339 void store_msgs(LEX *lc, RES_ITEM *item, int index, int pass)
340 {
341    int token;
342    char *cmd;
343    POOLMEM *dest;
344    int dest_len;
345 
346    Dmsg2(900, "store_msgs pass=%d code=%d\n", pass, item->code);
347    if (pass == 1) {
348       switch (item->code) {
349       case MD_STDOUT:
350       case MD_STDERR:
351       case MD_SYSLOG:              /* syslog */
352       case MD_CONSOLE:
353       case MD_CATALOG:
354          scan_types(lc, (MSGS *)(item->value), item->code, NULL, NULL);
355          break;
356       case MD_OPERATOR:            /* send to operator */
357       case MD_DIRECTOR:            /* send to Director */
358       case MD_MAIL:                /* mail */
359       case MD_MAIL_ON_ERROR:       /* mail if Job errors */
360       case MD_MAIL_ON_SUCCESS:     /* mail if Job succeeds */
361          if (item->code == MD_OPERATOR) {
362             cmd = res_all.res_msgs.operator_cmd;
363          } else {
364             cmd = res_all.res_msgs.mail_cmd;
365          }
366          dest = get_pool_memory(PM_MESSAGE);
367          dest[0] = 0;
368          dest_len = 0;
369          /* Pick up comma separated list of destinations */
370          for ( ;; ) {
371             token = lex_get_token(lc, T_NAME);   /* scan destination */
372             dest = check_pool_memory_size(dest, dest_len + lc->str_len + 2);
373             if (dest[0] != 0) {
374                pm_strcat(dest, " ");  /* separate multiple destinations with space */
375                dest_len++;
376             }
377             pm_strcat(dest, lc->str);
378             dest_len += lc->str_len;
379             Dmsg2(900, "store_msgs newdest=%s: dest=%s:\n", lc->str, NPRT(dest));
380             token = lex_get_token(lc, T_SKIP_EOL);
381             if (token == T_COMMA) {
382                continue;           /* get another destination */
383             }
384             if (token != T_EQUALS) {
385                scan_err1(lc, _("expected an =, got: %s"), lc->str);
386                return;
387             }
388             break;
389          }
390          Dmsg1(900, "mail_cmd=%s\n", NPRT(cmd));
391          scan_types(lc, (MSGS *)(item->value), item->code, dest, cmd);
392          free_pool_memory(dest);
393          Dmsg0(900, "done with dest codes\n");
394          break;
395 
396       case MD_FILE:                /* file */
397       case MD_APPEND:              /* append */
398          dest = get_pool_memory(PM_MESSAGE);
399          /* Pick up a single destination */
400          token = lex_get_token(lc, T_NAME);   /* scan destination */
401          pm_strcpy(dest, lc->str);
402          dest_len = lc->str_len;
403          token = lex_get_token(lc, T_SKIP_EOL);
404          Dmsg1(900, "store_msgs dest=%s:\n", NPRT(dest));
405          if (token != T_EQUALS) {
406             scan_err1(lc, _("expected an =, got: %s"), lc->str);
407             return;
408          }
409          scan_types(lc, (MSGS *)(item->value), item->code, dest, NULL);
410          free_pool_memory(dest);
411          Dmsg0(900, "done with dest codes\n");
412          break;
413 
414       default:
415          scan_err1(lc, _("Unknown item code: %d\n"), item->code);
416          return;
417       }
418    }
419    scan_to_eol(lc);
420    set_bit(index, res_all.hdr.item_present);
421    Dmsg0(900, "Done store_msgs\n");
422 }
423 
424 /*
425  * Scan for message types and add them to the message
426  * destination. The basic job here is to connect message types
427  *  (WARNING, ERROR, FATAL, INFO, ...) with an appropriate
428  *  destination (MAIL, FILE, OPERATOR, ...)
429  */
scan_types(LEX * lc,MSGS * msg,int dest_code,char * where,char * cmd)430 static void scan_types(LEX *lc, MSGS *msg, int dest_code, char *where, char *cmd)
431 {
432    int i;
433    bool found, is_not;
434    int msg_type = 0;
435    char *str;
436 
437    for ( ;; ) {
438       lex_get_token(lc, T_NAME);            /* expect at least one type */
439       found = false;
440       if (lc->str[0] == '!') {
441          is_not = true;
442          str = &lc->str[1];
443       } else {
444          is_not = false;
445          str = &lc->str[0];
446       }
447       for (i=0; msg_types[i].name; i++) {
448          if (strcasecmp(str, msg_types[i].name) == 0) {
449             msg_type = msg_types[i].token;
450             found = true;
451             break;
452          }
453       }
454       /* Custom event, we add it to the list for this Message */
455       if (!found && strncasecmp(str, "events.", 6) == 0) {
456          msg_type = msg->add_custom_type(is_not, str+7); /* We can ignore completely if we want */
457          Dmsg2(50, "Add events %s => %d\n", str, msg_type);
458          if (msg_type < 0) {
459             scan_err2(lc, _("message type: Unable to add %s message type. %s"), str,
460                       (msg_type == -1) ? "Too much custom type" : "Invalid format");
461             return;
462          }
463          found = true;
464       }
465       if (!found) {
466          scan_err1(lc, _("message type: %s not found"), str);
467          return;
468       }
469 
470       if (msg_type == M_MAX+1) {         /* all? */
471          for (i=3; i<=M_MAX; i++) {      /* yes set all types except Debug, Saved and Events */
472             add_msg_dest(msg, dest_code, msg_types[i].token, where, cmd);
473          }
474       } else if (is_not) {
475          rem_msg_dest(msg, dest_code, msg_type, where);
476       } else {
477          add_msg_dest(msg, dest_code, msg_type, where, cmd);
478       }
479       if (lc->ch != ',') {
480          break;
481       }
482       Dmsg0(900, "call lex_get_token() to eat comma\n");
483       lex_get_token(lc, T_ALL);          /* eat comma */
484    }
485    Dmsg0(900, "Done scan_types()\n");
486 }
487 
488 
489 /*
490  * This routine is ONLY for resource names
491  *  Store a name at specified address.
492  */
store_name(LEX * lc,RES_ITEM * item,int index,int pass)493 void store_name(LEX *lc, RES_ITEM *item, int index, int pass)
494 {
495    POOLMEM *msg = get_pool_memory(PM_EMSG);
496 
497    lex_get_token(lc, T_NAME);
498    if (!is_name_valid(lc->str, &msg)) {
499       scan_err1(lc, "%s\n", msg);
500       return;
501    }
502    free_pool_memory(msg);
503    /* Store the name both pass 1 and pass 2 */
504    if (*(item->value)) {
505       scan_err5(lc, _("Attempt to redefine \"%s\" from \"%s\" to \"%s\" referenced on line %d : %s\n"),
506          item->name, *(item->value), lc->str, lc->line_no, lc->line);
507       return;
508    }
509    *(item->value) = bstrdup(lc->str);
510    scan_to_eol(lc);
511    set_bit(index, res_all.hdr.item_present);
512 }
513 
514 
515 /*
516  * Store a name string at specified address
517  * A name string is limited to MAX_RES_NAME_LENGTH
518  */
store_strname(LEX * lc,RES_ITEM * item,int index,int pass)519 void store_strname(LEX *lc, RES_ITEM *item, int index, int pass)
520 {
521    lex_get_token(lc, T_NAME);
522    /* Store the name */
523    if (pass == 1) {
524       if (*(item->value)) {
525          scan_err5(lc, _("Attempt to redefine \"%s\" from \"%s\" to \"%s\" referenced on line %d : %s\n"),
526             item->name, *(item->value), lc->str, lc->line_no, lc->line);
527          return;
528       }
529       *(item->value) = bstrdup(lc->str);
530    }
531    scan_to_eol(lc);
532    set_bit(index, res_all.hdr.item_present);
533 }
534 
535 /* Store a string at specified address */
store_str(LEX * lc,RES_ITEM * item,int index,int pass)536 void store_str(LEX *lc, RES_ITEM *item, int index, int pass)
537 {
538    lex_get_token(lc, T_STRING);
539    if (pass == 1) {
540       if (*(item->value) && (item->flags & ITEM_ALLOW_DUPS)) {
541          free(*(item->value));
542          *(item->value) = NULL;
543       }
544       if (*(item->value)) {
545          scan_err5(lc, _("Attempt to redefine \"%s\" from \"%s\" to \"%s\" referenced on line %d : %s\n"),
546             item->name, *(item->value), lc->str, lc->line_no, lc->line);
547          return;
548       }
549       *(item->value) = bstrdup(lc->str);
550    }
551    scan_to_eol(lc);
552    set_bit(index, res_all.hdr.item_present);
553 }
554 
555 /*
556  * Store a directory name at specified address. Note, we do
557  *   shell expansion except if the string begins with a vertical
558  *   bar (i.e. it will likely be passed to the shell later).
559  */
store_dir(LEX * lc,RES_ITEM * item,int index,int pass)560 void store_dir(LEX *lc, RES_ITEM *item, int index, int pass)
561 {
562    lex_get_token(lc, T_STRING);
563    if (pass == 1) {
564       if (lc->str[0] != '|') {
565          do_shell_expansion(lc->str, sizeof_pool_memory(lc->str));
566       }
567 #ifdef STANDARDIZED_DIRECTORY_USAGE
568       // TODO ASX we should store all directory without the ending slash to
569       // avoid the need of testing its presence
570       int len=strlen(lc->str);
571       if (len>0 && IsPathSeparator(lc->str[len-1])) {
572          lc->str[len-1]='\0';
573       }
574 #endif
575       if (*(item->value)) {
576          scan_err5(lc, _("Attempt to redefine \"%s\" from \"%s\" to \"%s\" referenced on line %d : %s\n"),
577             item->name, *(item->value), lc->str, lc->line_no, lc->line);
578          return;
579       }
580       *(item->value) = bstrdup(lc->str);
581    }
582    scan_to_eol(lc);
583    set_bit(index, res_all.hdr.item_present);
584 }
585 
586 
587 /* Store a password specified address in MD5 coding */
store_password(LEX * lc,RES_ITEM * item,int index,int pass)588 void store_password(LEX *lc, RES_ITEM *item, int index, int pass)
589 {
590    unsigned int i, j;
591    struct MD5Context md5c;
592    unsigned char digest[CRYPTO_DIGEST_MD5_SIZE];
593    char sig[100];
594 
595    if (lc->options & LOPT_NO_MD5) {
596       store_str(lc, item, index, pass);
597 
598    } else {
599       lex_get_token(lc, T_STRING);
600       if (pass == 1) {
601          MD5Init(&md5c);
602          MD5Update(&md5c, (unsigned char *) (lc->str), lc->str_len);
603          MD5Final(digest, &md5c);
604          for (i = j = 0; i < sizeof(digest); i++) {
605             sprintf(&sig[j], "%02x", digest[i]);
606             j += 2;
607          }
608          if (*(item->value)) {
609             scan_err5(lc, _("Attempt to redefine \"%s\" from \"%s\" to \"%s\" referenced on line %d : %s\n"),
610                item->name, *(item->value), lc->str, lc->line_no, lc->line);
611             return;
612          }
613          *(item->value) = bstrdup(sig);
614       }
615       scan_to_eol(lc);
616       set_bit(index, res_all.hdr.item_present);
617    }
618 }
619 
620 
621 /* Store a resource at specified address.
622  * If we are in pass 2, do a lookup of the
623  * resource.
624  */
store_res(LEX * lc,RES_ITEM * item,int index,int pass)625 void store_res(LEX *lc, RES_ITEM *item, int index, int pass)
626 {
627    RES *res;
628 
629    lex_get_token(lc, T_NAME);
630    if (pass == 2) {
631       res = GetResWithName(item->code, lc->str);
632       if (res == NULL) {
633          scan_err3(lc, _("Could not find config Resource \"%s\" referenced on line %d : %s\n"),
634             lc->str, lc->line_no, lc->line);
635          return;
636       }
637       if (*(item->value)) {
638          scan_err3(lc, _("Attempt to redefine resource \"%s\" referenced on line %d : %s\n"),
639             item->name, lc->line_no, lc->line);
640          return;
641       }
642       *(item->value) = (char *)res;
643    }
644    scan_to_eol(lc);
645    set_bit(index, res_all.hdr.item_present);
646 }
647 
648 /*
649  * Store a resource pointer in an alist. default_value indicates how many
650  *   times this routine can be called -- i.e. how many alists
651  *   there are.
652  * If we are in pass 2, do a lookup of the
653  *   resource.
654  */
store_alist_res(LEX * lc,RES_ITEM * item,int index,int pass)655 void store_alist_res(LEX *lc, RES_ITEM *item, int index, int pass)
656 {
657    RES *res;
658    int count = item->default_value;
659    int i = 0;
660    alist *list;
661 
662    if (pass == 2) {
663       if (count == 0) {               /* always store in item->value */
664          i = 0;
665          if ((item->value)[i] == NULL) {
666             list = New(alist(10, not_owned_by_alist));
667          } else {
668             list = (alist *)(item->value)[i];
669          }
670       } else {
671          /* Find empty place to store this directive */
672          while ((item->value)[i] != NULL && i++ < count) { }
673          if (i >= count) {
674             scan_err4(lc, _("Too many %s directives. Max. is %d. line %d: %s\n"),
675                lc->str, count, lc->line_no, lc->line);
676             return;
677          }
678          list = New(alist(10, not_owned_by_alist));
679       }
680 
681       for (;;) {
682          lex_get_token(lc, T_NAME);   /* scan next item */
683          res = GetResWithName(item->code, lc->str);
684          if (res == NULL) {
685             scan_err3(lc, _("Could not find config Resource \"%s\" referenced on line %d : %s\n"),
686                lc->str, lc->line_no, lc->line);
687             return;
688          }
689          Dmsg5(900, "Append %p to alist %p size=%d i=%d %s\n",
690                res, list, list->size(), i, item->name);
691          list->append(res);
692          (item->value)[i] = (char *)list;
693          if (lc->ch != ',') {         /* if no other item follows */
694             if (!lex_check_eol(lc)) {
695                /* found garbage at the end of the line */
696                scan_err3(lc, _("Found unexpected characters resource list in Directive \"%s\" at the end of line %d : %s\n"),
697                   item->name, lc->line_no, lc->line);
698             }
699             break;                    /* get out */
700          }
701          lex_get_token(lc, T_ALL);    /* eat comma */
702       }
703    }
704    scan_to_eol(lc);
705    set_bit(index, res_all.hdr.item_present);
706 }
707 
708 
709 /*
710  * Store a string in an alist.
711  */
store_alist_str(LEX * lc,RES_ITEM * item,int index,int pass)712 void store_alist_str(LEX *lc, RES_ITEM *item, int index, int pass)
713 {
714    alist *list;
715 
716    if (pass == 2) {
717       if (*(item->value) == NULL) {
718          list = New(alist(10, owned_by_alist));
719          *(item->value) = (char *)list;
720       } else {
721          list = (alist *)(*(item->value));
722       }
723       for (;;) {
724          lex_get_token(lc, T_STRING);   /* scan next item */
725          Dmsg4(900, "Append %s to alist 0x%p size=%d %s\n",
726             lc->str, list, list->size(), item->name);
727          list->append(bstrdup(lc->str));
728          if (lc->ch != ',') {         /* if no other item follows */
729             if (!lex_check_eol(lc)) {
730                /* found garbage at the end of the line */
731                scan_err3(lc, _("Found unexpected characters in resource list in Directive \"%s\" at the end of line %d : %s\n"),
732                   item->name, lc->line_no, lc->line);
733             }
734             break;                    /* get out */
735          }
736          lex_get_token(lc, T_ALL);    /* eat comma */
737       }
738    }
739    scan_to_eol(lc);
740    set_bit(index, res_all.hdr.item_present);
741 }
742 
743 
744 
745 /*
746  * Store default values for Resource from xxxDefs
747  * If we are in pass 2, do a lookup of the
748  * resource and store everything not explicitly set
749  * in main resource.
750  *
751  * Note, here item points to the main resource (e.g. Job, not
752  *  the jobdefs, which we look up).
753  */
store_defs(LEX * lc,RES_ITEM * item,int index,int pass)754 void store_defs(LEX *lc, RES_ITEM *item, int index, int pass)
755 {
756    RES *res;
757 
758    lex_get_token(lc, T_NAME);
759    if (pass == 2) {
760      Dmsg2(900, "Code=%d name=%s\n", item->code, lc->str);
761      res = GetResWithName(item->code, lc->str);
762      if (res == NULL) {
763         scan_err3(lc, _("Missing config Resource \"%s\" referenced on line %d : %s\n"),
764            lc->str, lc->line_no, lc->line);
765         return;
766      }
767    }
768    scan_to_eol(lc);
769 }
770 
771 
772 
773 /* Store an integer at specified address */
store_int32(LEX * lc,RES_ITEM * item,int index,int pass)774 void store_int32(LEX *lc, RES_ITEM *item, int index, int pass)
775 {
776    lex_get_token(lc, T_INT32);
777    *(uint32_t *)(item->value) = lc->int32_val;
778    scan_to_eol(lc);
779    set_bit(index, res_all.hdr.item_present);
780 }
781 
782 /* Store a positive integer at specified address */
store_pint32(LEX * lc,RES_ITEM * item,int index,int pass)783 void store_pint32(LEX *lc, RES_ITEM *item, int index, int pass)
784 {
785    lex_get_token(lc, T_PINT32);
786    *(uint32_t *)(item->value) = lc->pint32_val;
787    scan_to_eol(lc);
788    set_bit(index, res_all.hdr.item_present);
789 }
790 
791 
792 /* Store an 64 bit integer at specified address */
store_int64(LEX * lc,RES_ITEM * item,int index,int pass)793 void store_int64(LEX *lc, RES_ITEM *item, int index, int pass)
794 {
795    lex_get_token(lc, T_INT64);
796    *(int64_t *)(item->value) = lc->int64_val;
797    scan_to_eol(lc);
798    set_bit(index, res_all.hdr.item_present);
799 }
800 
801 enum store_unit_type {
802    STORE_SIZE,
803    STORE_SPEED
804 } ;
805 
806 /*
807  * This routine stores either a 32 or a 64 bit value (size32)
808  *  and either a size (in bytes) or a speed (bytes per second).
809  */
store_int_unit(LEX * lc,RES_ITEM * item,int index,int pass,bool size32,enum store_unit_type type)810 static void store_int_unit(LEX *lc, RES_ITEM *item, int index, int pass,
811                            bool size32, enum store_unit_type type)
812 {
813    int token;
814    uint64_t uvalue;
815    char bsize[500];
816 
817    Dmsg0(900, "Enter store_unit\n");
818    token = lex_get_token(lc, T_SKIP_EOL);
819    errno = 0;
820    switch (token) {
821    case T_NUMBER:
822    case T_IDENTIFIER:
823    case T_UNQUOTED_STRING:
824       bstrncpy(bsize, lc->str, sizeof(bsize));  /* save first part */
825       /* if terminated by space, scan and get modifier */
826       while (lc->ch == ' ') {
827          token = lex_get_token(lc, T_ALL);
828          switch (token) {
829          case T_NUMBER:
830          case T_IDENTIFIER:
831          case T_UNQUOTED_STRING:
832             bstrncat(bsize, lc->str, sizeof(bsize));
833             break;
834          }
835       }
836       if (type == STORE_SIZE) {
837          if (!size_to_uint64(bsize, strlen(bsize), &uvalue)) {
838             scan_err1(lc, _("expected a size number, got: %s"), lc->str);
839             return;
840          }
841       } else {
842          if (!speed_to_uint64(bsize, strlen(bsize), &uvalue)) {
843             scan_err1(lc, _("expected a speed number, got: %s"), lc->str);
844             return;
845          }
846       }
847       if (size32) {
848          *(uint32_t *)(item->value) = (uint32_t)uvalue;
849       } else {
850          *(uint64_t *)(item->value) = uvalue;
851       }
852       break;
853    default:
854       scan_err2(lc, _("expected a %s, got: %s"),
855                 (type == STORE_SIZE)?_("size"):_("speed"), lc->str);
856       return;
857    }
858    if (token != T_EOL) {
859       scan_to_eol(lc);
860    }
861    set_bit(index, res_all.hdr.item_present);
862    Dmsg0(900, "Leave store_unit\n");
863 }
864 
865 /* Store a size in bytes */
store_size32(LEX * lc,RES_ITEM * item,int index,int pass)866 void store_size32(LEX *lc, RES_ITEM *item, int index, int pass)
867 {
868    store_int_unit(lc, item, index, pass, true /* 32 bit */, STORE_SIZE);
869 }
870 
871 /* Store a size in bytes */
store_size64(LEX * lc,RES_ITEM * item,int index,int pass)872 void store_size64(LEX *lc, RES_ITEM *item, int index, int pass)
873 {
874    store_int_unit(lc, item, index, pass, false /* not 32 bit */, STORE_SIZE);
875 }
876 
877 /* Store a speed in bytes/s */
store_speed(LEX * lc,RES_ITEM * item,int index,int pass)878 void store_speed(LEX *lc, RES_ITEM *item, int index, int pass)
879 {
880    store_int_unit(lc, item, index, pass, false /* 64 bit */, STORE_SPEED);
881 }
882 
883 /* Store a time period in seconds */
store_time(LEX * lc,RES_ITEM * item,int index,int pass)884 void store_time(LEX *lc, RES_ITEM *item, int index, int pass)
885 {
886    int token;
887    utime_t utime;
888    char period[500];
889 
890    token = lex_get_token(lc, T_SKIP_EOL);
891    errno = 0;
892    switch (token) {
893    case T_NUMBER:
894    case T_IDENTIFIER:
895    case T_UNQUOTED_STRING:
896       bstrncpy(period, lc->str, sizeof(period));  /* get first part */
897       /* if terminated by space, scan and get modifier */
898       while (lc->ch == ' ') {
899          token = lex_get_token(lc, T_ALL);
900          switch (token) {
901          case T_NUMBER:
902          case T_IDENTIFIER:
903          case T_UNQUOTED_STRING:
904             bstrncat(period, lc->str, sizeof(period));
905             break;
906          }
907       }
908       if (!duration_to_utime(period, &utime)) {
909          scan_err1(lc, _("expected a time period, got: %s"), period);
910          return;
911       }
912       *(utime_t *)(item->value) = utime;
913       break;
914    default:
915       scan_err1(lc, _("expected a time period, got: %s"), lc->str);
916       return;
917    }
918    if (token != T_EOL) {
919       scan_to_eol(lc);
920    }
921    set_bit(index, res_all.hdr.item_present);
922 }
923 
924 
925 /* Store a yes/no in a bit field */
store_bit(LEX * lc,RES_ITEM * item,int index,int pass)926 void store_bit(LEX *lc, RES_ITEM *item, int index, int pass)
927 {
928    lex_get_token(lc, T_NAME);
929    if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
930       *(uint32_t *)(item->value) |= item->code;
931    } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
932       *(uint32_t *)(item->value) &= ~(item->code);
933    } else {
934       scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
935       return;
936    }
937    scan_to_eol(lc);
938    set_bit(index, res_all.hdr.item_present);
939 }
940 
941 /* Store a bool in a bit field */
store_bool(LEX * lc,RES_ITEM * item,int index,int pass)942 void store_bool(LEX *lc, RES_ITEM *item, int index, int pass)
943 {
944    lex_get_token(lc, T_NAME);
945    if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
946       *(bool *)(item->value) = true;
947    } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
948       *(bool *)(item->value) = false;
949    } else {
950       scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
951       return;
952    }
953    scan_to_eol(lc);
954    set_bit(index, res_all.hdr.item_present);
955 }
956 
957 
958 /*
959  * Store Tape Label Type (Bacula, ANSI, IBM)
960  *
961  */
store_label(LEX * lc,RES_ITEM * item,int index,int pass)962 void store_label(LEX *lc, RES_ITEM *item, int index, int pass)
963 {
964    int i;
965 
966    lex_get_token(lc, T_NAME);
967    /* Store the label pass 2 so that type is defined */
968    for (i=0; tapelabels[i].name; i++) {
969       if (strcasecmp(lc->str, tapelabels[i].name) == 0) {
970          *(uint32_t *)(item->value) = tapelabels[i].token;
971          i = 0;
972          break;
973       }
974    }
975    if (i != 0) {
976       scan_err1(lc, _("Expected a Tape Label keyword, got: %s"), lc->str);
977       return;
978    }
979    scan_to_eol(lc);
980    set_bit(index, res_all.hdr.item_present);
981 }
982 
983 /*
984  * Store Statistics Type (CSV, Graphite - only supported)
985  */
store_coll_type(LEX * lc,RES_ITEM * item,int index,int pass)986 void store_coll_type(LEX *lc, RES_ITEM *item, int index, int pass)
987 {
988    int i;
989 
990    lex_get_token(lc, T_NAME);
991    /* Store the type both pass 1 and pass 2 */
992    for (i = 0; collectortypes[i].type_name; i++) {
993       if (strcasecmp(lc->str, collectortypes[i].type_name) == 0) {
994          *(int32_t *)(item->value) = collectortypes[i].coll_type;
995          i = 0;
996          break;
997       }
998    }
999    if (i != 0) {
1000       scan_err1(lc, _("Expected a Statistics backend type keyword, got: %s"), lc->str);
1001    }
1002    scan_to_eol(lc);
1003    set_bit(index, res_all.hdr.item_present);
1004 }
1005 
1006 
1007 /*
1008  *
1009  *  Configuration parser for Director Run Configuration
1010  *   directives, which are part of the Schedule Resource
1011  *
1012  *     Kern Sibbald, May MM
1013  *
1014  */
1015 
1016 enum e_state {
1017    s_none = 0,
1018    s_range,
1019    s_mday,
1020    s_month,
1021    s_time,
1022    s_at,
1023    s_wday,
1024    s_daily,
1025    s_weekly,
1026    s_monthly,
1027    s_hourly,
1028    s_wom,                           /* 1st, 2nd, ...*/
1029    s_woy,                           /* week of year w00 - w53 */
1030    s_ldom                           /* last day of month */
1031 };
1032 
1033 struct s_keyw {
1034   const char *name;                   /* keyword */
1035   enum e_state state;                 /* parser state */
1036   int code;                           /* state value */
1037 };
1038 
1039 /* Keywords understood by parser */
1040 static struct s_keyw keyw[] = {
1041   {NT_("on"),         s_none,    0},
1042   {NT_("at"),         s_at,      0},
1043   {NT_("lastday"),    s_ldom,    0},
1044 
1045   {NT_("sun"),        s_wday,    0},
1046   {NT_("mon"),        s_wday,    1},
1047   {NT_("tue"),        s_wday,    2},
1048   {NT_("wed"),        s_wday,    3},
1049   {NT_("thu"),        s_wday,    4},
1050   {NT_("fri"),        s_wday,    5},
1051   {NT_("sat"),        s_wday,    6},
1052   {NT_("jan"),        s_month,   0},
1053   {NT_("feb"),        s_month,   1},
1054   {NT_("mar"),        s_month,   2},
1055   {NT_("apr"),        s_month,   3},
1056   {NT_("may"),        s_month,   4},
1057   {NT_("jun"),        s_month,   5},
1058   {NT_("jul"),        s_month,   6},
1059   {NT_("aug"),        s_month,   7},
1060   {NT_("sep"),        s_month,   8},
1061   {NT_("oct"),        s_month,   9},
1062   {NT_("nov"),        s_month,  10},
1063   {NT_("dec"),        s_month,  11},
1064 
1065   {NT_("sunday"),     s_wday,    0},
1066   {NT_("monday"),     s_wday,    1},
1067   {NT_("tuesday"),    s_wday,    2},
1068   {NT_("wednesday"),  s_wday,    3},
1069   {NT_("thursday"),   s_wday,    4},
1070   {NT_("friday"),     s_wday,    5},
1071   {NT_("saturday"),   s_wday,    6},
1072   {NT_("january"),    s_month,   0},
1073   {NT_("february"),   s_month,   1},
1074   {NT_("march"),      s_month,   2},
1075   {NT_("april"),      s_month,   3},
1076   {NT_("june"),       s_month,   5},
1077   {NT_("july"),       s_month,   6},
1078   {NT_("august"),     s_month,   7},
1079   {NT_("september"),  s_month,   8},
1080   {NT_("october"),    s_month,   9},
1081   {NT_("november"),   s_month,  10},
1082   {NT_("december"),   s_month,  11},
1083 
1084   {NT_("daily"),      s_daily,   0},
1085   {NT_("weekly"),     s_weekly,  0},
1086   {NT_("monthly"),    s_monthly, 0},
1087   {NT_("hourly"),     s_hourly,  0},
1088 
1089   {NT_("1st"),        s_wom,     0},
1090   {NT_("2nd"),        s_wom,     1},
1091   {NT_("3rd"),        s_wom,     2},
1092   {NT_("4th"),        s_wom,     3},
1093   {NT_("5th"),        s_wom,     4},
1094   {NT_("6th"),        s_wom,     5},
1095 
1096   {NT_("first"),      s_wom,     0},
1097   {NT_("second"),     s_wom,     1},
1098   {NT_("third"),      s_wom,     2},
1099   {NT_("fourth"),     s_wom,     3},
1100   {NT_("fifth"),      s_wom,     4},
1101   {NT_("sixth"),      s_wom,     5},
1102   {NULL,         s_none,    0}
1103 };
1104 
1105 static bool have_hour, have_mday, have_wday, have_month, have_wom;
1106 static bool have_at, have_woy;
1107 
set_defaults(RUNBASE * lrun)1108 static void set_defaults(RUNBASE *lrun) {
1109    have_hour = have_mday = have_wday = have_month = have_wom = have_woy = false;
1110    have_at = false;
1111    set_bits(0, 23, lrun->hour);
1112    set_bits(0, 30, lrun->mday);
1113    set_bits(0, 6,  lrun->wday);
1114    set_bits(0, 11, lrun->month);
1115    set_bits(0, 5,  lrun->wom);
1116    set_bits(0, 53, lrun->woy);
1117 }
1118 
copy(RUNBASE * src)1119 void RUNBASE::copy(RUNBASE *src)
1120 {
1121    minute = src->minute;
1122    last_run = src->last_run;
1123    next_run = src->next_run;
1124    last_day_set = src->last_day_set;
1125    memcpy(hour, src->hour, sizeof(hour));
1126    memcpy(mday, src->mday, sizeof(mday));
1127    memcpy(month,src->month,sizeof(month));
1128    memcpy(wday, src->wday, sizeof(wday));
1129    memcpy(wom,  src->wom,  sizeof(wom));
1130    memcpy(woy,  src->woy,  sizeof(woy));
1131 }
1132 
1133 /*
1134  * Store Schedule Run information
1135  *
1136  * Parse Run statement:
1137  *
1138  *  Run <keyword=value ...> [on] 2 january at 23:45
1139  *
1140  *   Default Run time is daily at 0:0
1141  *
1142  *   There can be multiple run statements, they are simply chained
1143  *   together at the upper level.
1144  *
1145  *   Look src/dird/run_conf.c to see how to use this function
1146  *
1147  */
store_runbase(LEX * lc,int token)1148 void RUNBASE::store_runbase(LEX *lc, int token)
1149 {
1150    int i;
1151    int state, state2 = 0, code = 0, code2 = 0;
1152    int options = lc->options;
1153    char *p;
1154    RUNBASE *lrun = this;
1155 
1156 
1157    lc->options |= LOPT_NO_IDENT;      /* want only "strings" */
1158 
1159    /* clear local copy of run record */
1160    clear();
1161 
1162    if (token == T_ERROR) {
1163       return;
1164    }
1165 
1166    /*
1167     * Scan schedule times.
1168     * Default is: daily at 0:0
1169     */
1170    state = s_none;
1171    set_defaults(lrun);
1172 
1173    for ( ; token != T_EOL; (token = lex_get_token(lc, T_ALL))) {
1174       int len;
1175       bool pm = false;
1176       bool am = false;
1177       switch (token) {
1178       case T_NUMBER:
1179          state = s_mday;
1180          code = atoi(lc->str) - 1;
1181          if (code < 0 || code > 30) {
1182             scan_err0(lc, _("Day number out of range (1-31)"));
1183          }
1184          break;
1185       case T_NAME:                 /* this handles drop through from keyword */
1186       case T_UNQUOTED_STRING:
1187          if (strchr(lc->str, (int)'-')) {
1188             state = s_range;
1189             break;
1190          }
1191          if (strchr(lc->str, (int)':')) {
1192             state = s_time;
1193             break;
1194          }
1195          if (lc->str_len == 3 && (lc->str[0] == 'w' || lc->str[0] == 'W') &&
1196              is_an_integer(lc->str+1)) {
1197             code = atoi(lc->str+1);
1198             if (code < 0 || code > 53) {
1199                scan_err0(lc, _("Week number out of range (0-53)"));
1200               /* NOT REACHED */
1201             }
1202             state = s_woy;            /* week of year */
1203             break;
1204          }
1205          /* everything else must be a keyword */
1206          for (i=0; keyw[i].name; i++) {
1207             if (strcasecmp(lc->str, keyw[i].name) == 0) {
1208                state = keyw[i].state;
1209                code   = keyw[i].code;
1210                i = 0;
1211                break;
1212             }
1213          }
1214          if (i != 0) {
1215             scan_err1(lc, _("Job type field: %s in run record not found"), lc->str);
1216             /* NOT REACHED */
1217          }
1218          break;
1219       case T_COMMA:
1220          continue;
1221       default:
1222          scan_err2(lc, _("Unexpected token: %d:%s"), token, lc->str);
1223          /* NOT REACHED */
1224          break;
1225       }
1226       switch (state) {
1227       case s_none:
1228          continue;
1229       case s_mday:                 /* day of month */
1230          if (!have_mday) {
1231             clear_bits(0, 30, lrun->mday);
1232             have_mday = true;
1233          }
1234          set_bit(code, lrun->mday);
1235          break;
1236       case s_month:                /* month of year */
1237          if (!have_month) {
1238             clear_bits(0, 11, lrun->month);
1239             have_month = true;
1240          }
1241          set_bit(code, lrun->month);
1242          break;
1243       case s_wday:                 /* week day */
1244          if (!have_wday) {
1245             clear_bits(0, 6, lrun->wday);
1246             have_wday = true;
1247          }
1248          set_bit(code, lrun->wday);
1249          break;
1250       case s_wom:                  /* Week of month 1st, ... */
1251          if (!have_wom) {
1252             clear_bits(0, 5, lrun->wom);
1253             have_wom = true;
1254          }
1255          set_bit(code, lrun->wom);
1256          break;
1257       case s_woy:
1258          if (!have_woy) {
1259             clear_bits(0, 53, lrun->woy);
1260             have_woy = true;
1261          }
1262          set_bit(code, lrun->woy);
1263          break;
1264       case s_time:                 /* time */
1265          if (!have_at) {
1266             scan_err0(lc, _("Time must be preceded by keyword AT."));
1267             /* NOT REACHED */
1268          }
1269          if (!have_hour) {
1270             clear_bits(0, 23, lrun->hour);
1271          }
1272 //       Dmsg1(000, "s_time=%s\n", lc->str);
1273          p = strchr(lc->str, ':');
1274          if (!p)  {
1275             scan_err0(lc, _("Time logic error.\n"));
1276             /* NOT REACHED */
1277          }
1278          *p++ = 0;                 /* separate two halves */
1279          code = atoi(lc->str);     /* pick up hour */
1280          code2 = atoi(p);          /* pick up minutes */
1281          len = strlen(p);
1282          if (len >= 2) {
1283             p += 2;
1284          }
1285          if (strcasecmp(p, "pm") == 0) {
1286             pm = true;
1287          } else if (strcasecmp(p, "am") == 0) {
1288             am = true;
1289          } else if (len != 2) {
1290             scan_err0(lc, _("Bad time specification."));
1291             /* NOT REACHED */
1292          }
1293          /*
1294           * Note, according to NIST, 12am and 12pm are ambiguous and
1295           *  can be defined to anything.  However, 12:01am is the same
1296           *  as 00:01 and 12:01pm is the same as 12:01, so we define
1297           *  12am as 00:00 and 12pm as 12:00.
1298           */
1299          if (pm) {
1300             /* Convert to 24 hour time */
1301             if (code != 12) {
1302                code += 12;
1303             }
1304          /* am */
1305          } else if (am && code == 12) {
1306             code -= 12;
1307          }
1308          if (code < 0 || code > 23 || code2 < 0 || code2 > 59) {
1309             scan_err0(lc, _("Bad time specification."));
1310             /* NOT REACHED */
1311          }
1312 //       Dmsg2(000, "hour=%d min=%d\n", code, code2);
1313          set_bit(code, lrun->hour);
1314          lrun->minute = code2;
1315          have_hour = true;
1316          break;
1317       case s_at:
1318          have_at = true;
1319          break;
1320       case s_ldom:
1321          if (!have_mday) {
1322             clear_bits(0, 30, lrun->mday);
1323             have_mday = true;
1324          }
1325          lrun->last_day_set = true;
1326          set_bit(31, lrun->mday);   /* day 32 => last day of month */
1327          break;
1328       case s_range:
1329          p = strchr(lc->str, '-');
1330          if (!p) {
1331             scan_err0(lc, _("Range logic error.\n"));
1332          }
1333          *p++ = 0;                 /* separate two halves */
1334 
1335          /* Check for day range */
1336          if (is_an_integer(lc->str) && is_an_integer(p)) {
1337             code = atoi(lc->str) - 1;
1338             code2 = atoi(p) - 1;
1339             if (code < 0 || code > 30 || code2 < 0 || code2 > 30) {
1340                scan_err0(lc, _("Bad day range specification."));
1341             }
1342             if (!have_mday) {
1343                clear_bits(0, 30, lrun->mday);
1344                have_mday = true;
1345             }
1346             if (code < code2) {
1347                set_bits(code, code2, lrun->mday);
1348             } else {
1349                set_bits(code, 30, lrun->mday);
1350                set_bits(0, code2, lrun->mday);
1351             }
1352             break;
1353          }
1354          /* Check for week of year range */
1355          if (strlen(lc->str) == 3 && strlen(p) == 3 &&
1356              (lc->str[0] == 'w' || lc->str[0] == 'W') &&
1357              (p[0] == 'w' || p[0] == 'W') &&
1358              is_an_integer(lc->str+1) && is_an_integer(p+1)) {
1359             code = atoi(lc->str+1);
1360             code2 = atoi(p+1);
1361             if (code < 0 || code > 53 || code2 < 0 || code2 > 53) {
1362                scan_err0(lc, _("Week number out of range (0-53)"));
1363             }
1364             if (!have_woy) {
1365                clear_bits(0, 53, lrun->woy);
1366                have_woy = true;
1367             }
1368             if (code < code2) {
1369                set_bits(code, code2, lrun->woy);
1370             } else {
1371                set_bits(code, 53, lrun->woy);
1372                set_bits(0, code2, lrun->woy);
1373             }
1374             break;
1375          }
1376          /* lookup first half of keyword range (week days or months) */
1377          lcase(lc->str);
1378          for (i=0; keyw[i].name; i++) {
1379             if (strcasecmp(lc->str, keyw[i].name) == 0) {
1380                state = keyw[i].state;
1381                code   = keyw[i].code;
1382                i = 0;
1383                break;
1384             }
1385          }
1386          if (i != 0 || (state != s_month && state != s_wday && state != s_wom)) {
1387             scan_err0(lc, _("Invalid month, week or position day range"));
1388             /* NOT REACHED */
1389          }
1390 
1391          /* Lookup end of range */
1392          lcase(p);
1393          for (i=0; keyw[i].name; i++) {
1394             if (strcasecmp(p, keyw[i].name) == 0) {
1395                state2  = keyw[i].state;
1396                code2   = keyw[i].code;
1397                i = 0;
1398                break;
1399             }
1400          }
1401          if (i != 0 || state != state2 || code == code2) {
1402             scan_err0(lc, _("Invalid month, weekday or position range"));
1403             /* NOT REACHED */
1404          }
1405          if (state == s_wday) {
1406             if (!have_wday) {
1407                clear_bits(0, 6, lrun->wday);
1408                have_wday = true;
1409             }
1410             if (code < code2) {
1411                set_bits(code, code2, lrun->wday);
1412             } else {
1413                set_bits(code, 6, lrun->wday);
1414                set_bits(0, code2, lrun->wday);
1415             }
1416          } else if (state == s_month) {
1417             if (!have_month) {
1418                clear_bits(0, 11, lrun->month);
1419                have_month = true;
1420             }
1421             if (code < code2) {
1422                set_bits(code, code2, lrun->month);
1423             } else {
1424                /* this is a bit odd, but we accept it anyway */
1425                set_bits(code, 11, lrun->month);
1426                set_bits(0, code2, lrun->month);
1427             }
1428          } else {
1429             /* Must be position */
1430             if (!have_wom) {
1431                clear_bits(0, 5, lrun->wom);
1432                have_wom = true;
1433             }
1434             if (code < code2) {
1435                set_bits(code, code2, lrun->wom);
1436             } else {
1437                set_bits(code, 5, lrun->wom);
1438                set_bits(0, code2, lrun->wom);
1439             }
1440          }
1441          break;
1442       case s_hourly:
1443          have_hour = true;
1444          set_bits(0, 23, lrun->hour);
1445          break;
1446       case s_weekly:
1447          have_mday = have_wom = have_woy = true;
1448          set_bits(0, 30, lrun->mday);
1449          set_bits(0, 5,  lrun->wom);
1450          set_bits(0, 53, lrun->woy);
1451          break;
1452       case s_daily:
1453          have_mday = true;
1454          set_bits(0, 6, lrun->wday);
1455          break;
1456       case s_monthly:
1457          have_month = true;
1458          set_bits(0, 11, lrun->month);
1459          break;
1460       default:
1461          scan_err0(lc, _("Unexpected run state\n"));
1462          /* NOT REACHED */
1463          break;
1464       }
1465    }
1466 
1467    lc->options = options;             /* restore scanner options */
1468 }
1469 
1470 
1471 /* Parser state */
1472 enum parse_state {
1473    p_none,
1474    p_resource
1475 };
1476 
init(const char * cf,LEX_ERROR_HANDLER * scan_error,int32_t err_type,void * vres_all,int32_t res_all_size,int32_t r_first,int32_t r_last,RES_TABLE * resources,RES_HEAD *** res_head)1477 void CONFIG::init(
1478    const char *cf,
1479    LEX_ERROR_HANDLER *scan_error,
1480    int32_t err_type,
1481    void *vres_all,
1482    int32_t res_all_size,
1483    int32_t r_first,
1484    int32_t r_last,
1485    RES_TABLE *resources,
1486    RES_HEAD ***res_head)
1487 {
1488    m_cf = cf;
1489    m_scan_error = scan_error;
1490    m_err_type = err_type;
1491    m_res_all = vres_all;
1492    m_res_all_size = res_all_size;
1493    m_r_first = r_first;
1494    m_r_last = r_last;
1495    m_resources = resources;
1496    init_res_head(res_head, r_first, r_last);
1497    m_res_head = *res_head;
1498 }
1499 
1500 /*********************************************************************
1501  *
1502  * Parse configuration file
1503  *
1504  * Return 0 if reading failed, 1 otherwise
1505  *  Note, the default behavior unless you have set an alternate
1506  *  scan_error handler is to die on an error.
1507  */
parse_config()1508 bool CONFIG::parse_config()
1509 {
1510    LEX *lc = NULL;
1511    int token, i, pass;
1512    int res_type = 0;
1513    enum parse_state state = p_none;
1514    RES_ITEM *items = NULL;
1515    int level = 0;
1516    static bool first = true;
1517    int errstat;
1518    const char *cf = m_cf;
1519    LEX_ERROR_HANDLER *scan_error = m_scan_error;
1520    int err_type = m_err_type;
1521    //HPKT hpkt;
1522 
1523    if (first && (errstat=rwl_init(&res_lock)) != 0) {
1524       berrno be;
1525       Jmsg1(NULL, M_ABORT, 0, _("Unable to initialize resource lock. ERR=%s\n"),
1526             be.bstrerror(errstat));
1527    }
1528    first = false;
1529 
1530    char *full_path = (char *)alloca(MAX_PATH + 1);
1531 
1532    if (!find_config_file(cf, full_path, MAX_PATH +1)) {
1533       Jmsg0(NULL, M_ABORT, 0, _("Config filename too long.\n"));
1534    }
1535    cf = full_path;
1536 
1537    /* Make two passes. The first builds the name symbol table,
1538     * and the second picks up the items.
1539     */
1540    Dmsg0(900, "Enter parse_config()\n");
1541    for (pass=1; pass <= 2; pass++) {
1542       Dmsg1(900, "parse_config pass %d\n", pass);
1543       if ((lc = lex_open_file(lc, cf, scan_error)) == NULL) {
1544          berrno be;
1545          /* We must create a lex packet to print the error */
1546          lc = (LEX *)malloc(sizeof(LEX));
1547          memset(lc, 0, sizeof(LEX));
1548          lc->str = get_memory(5000);
1549          if (scan_error) {
1550             lc->scan_error = scan_error;
1551          } else {
1552             lex_set_default_error_handler(lc);
1553          }
1554          lex_set_error_handler_error_type(lc, err_type) ;
1555          pm_strcpy(lc->str, cf);
1556          lc->fname = lc->str;
1557          scan_err2(lc, _("Cannot open config file \"%s\": %s\n"),
1558             lc->str, be.bstrerror());
1559          free_pool_memory(lc->str);
1560          free(lc);
1561          return 0;
1562       }
1563       if (!m_encode_pass) {
1564          lex_store_clear_passwords(lc);
1565       }
1566       lex_set_error_handler_error_type(lc, err_type) ;
1567       while ((token=lex_get_token(lc, T_ALL)) != T_EOF) {
1568          Dmsg3(900, "parse state=%d pass=%d got token=%s\n", state, pass,
1569               lex_tok_to_str(token));
1570          switch (state) {
1571          case p_none:
1572             if (token == T_EOL) {
1573                break;
1574             } else if (token == T_UTF8_BOM) {
1575                /* We can assume the file is UTF-8 as we have seen a UTF-8 BOM */
1576                break;
1577             } else if (token == T_UTF16_BOM) {
1578                scan_err0(lc, _("Currently we cannot handle UTF-16 source files. "
1579                    "Please convert the conf file to UTF-8\n"));
1580                goto bail_out;
1581             } else if (token != T_IDENTIFIER) {
1582                scan_err1(lc, _("Expected a Resource name identifier, got: %s"), lc->str);
1583                goto bail_out;
1584             }
1585             for (i=0; resources[i].name; i++) {
1586                if (strcasecmp(resources[i].name, lc->str) == 0) {
1587                   items = resources[i].items;
1588                   if (!items) {
1589                      break;
1590                   }
1591                   state = p_resource;
1592                   res_type = resources[i].rcode;
1593                   init_resource0(this, res_type, items, pass);
1594                   break;
1595                }
1596             }
1597             if (state == p_none) {
1598                scan_err1(lc, _("expected resource name, got: %s"), lc->str);
1599                goto bail_out;
1600             }
1601             break;
1602          case p_resource:
1603             switch (token) {
1604             case T_BOB:
1605                level++;
1606                break;
1607             case T_IDENTIFIER:
1608                if (level != 1) {
1609                   scan_err1(lc, _("not in resource definition: %s"), lc->str);
1610                   goto bail_out;
1611                }
1612                for (i=0; items[i].name; i++) {
1613                   //hpkt.pass = pass;
1614                   //hpkt.ritem = &items[i];
1615                   //hpkt.edbuf = NULL;
1616                   //hpkt.index = i;
1617                   //hpkt.lc = lc;
1618                   //hpkt.hfunc = HF_STORE;
1619                   if (strcasecmp(items[i].name, lc->str) == 0) {
1620                      /* If the ITEM_NO_EQUALS flag is set we do NOT
1621                       *   scan for = after the keyword  */
1622                      if (!(items[i].flags & ITEM_NO_EQUALS)) {
1623                         token = lex_get_token(lc, T_SKIP_EOL);
1624                         Dmsg1 (900, "in T_IDENT got token=%s\n", lex_tok_to_str(token));
1625                         if (token != T_EQUALS) {
1626                            scan_err1(lc, _("expected an equals, got: %s"), lc->str);
1627                            goto bail_out;
1628                         }
1629                      }
1630                      Dmsg1(800, "calling handler for %s\n", items[i].name);
1631                      /* Call item handler */
1632                      items[i].handler(lc, &items[i], i, pass);
1633                      i = -1;
1634                      break;
1635                   }
1636                }
1637                if (i >= 0) {
1638                   Dmsg2(900, "level=%d id=%s\n", level, lc->str);
1639                   Dmsg1(900, "Keyword = %s\n", lc->str);
1640                   scan_err1(lc, _("Keyword \"%s\" not permitted in this resource.\n"
1641                      "Perhaps you left the trailing brace off of the previous resource."), lc->str);
1642                   goto bail_out;
1643                }
1644                break;
1645 
1646             case T_EOB:
1647                level--;
1648                state = p_none;
1649                Dmsg0(900, "T_EOB => define new resource\n");
1650                if (res_all.hdr.name == NULL) {
1651                   scan_err0(lc, _("Name not specified for resource"));
1652                   goto bail_out;
1653                }
1654                if (!save_resource(this, res_type, items, pass)) {  /* save resource */
1655                   scan_err1(lc, "%s", m_errmsg);
1656                   goto bail_out;
1657                }
1658                break;
1659 
1660             case T_EOL:
1661                break;
1662 
1663             default:
1664                scan_err2(lc, _("unexpected token %d %s in resource definition"),
1665                   token, lex_tok_to_str(token));
1666                goto bail_out;
1667             }
1668             break;
1669          default:
1670             scan_err1(lc, _("Unknown parser state %d\n"), state);
1671             goto bail_out;
1672          }
1673       }
1674       if (state != p_none) {
1675          scan_err0(lc, _("End of conf file reached with unclosed resource."));
1676          goto bail_out;
1677       }
1678       if (chk_dbglvl(900) && pass == 2) {
1679          int i;
1680          for (i=m_r_first; i<=m_r_last; i++) {
1681             dump_each_resource(i, prtmsg, NULL);
1682          }
1683       }
1684       lc = lex_close_file(lc);
1685    }
1686    Dmsg0(900, "Leave parse_config()\n");
1687    return 1;
1688 bail_out:
1689    if (lc) {
1690       lc = lex_close_file(lc);
1691    }
1692    return 0;
1693 }
1694 
get_default_configdir()1695 const char *get_default_configdir()
1696 {
1697    return SYSCONFDIR;
1698 }
1699 
1700 #ifdef xxx_not_used
1701    HRESULT hr;
1702    static char szConfigDir[MAX_PATH + 1] = { 0 };
1703    if (!p_SHGetFolderPath) {
1704       bstrncpy(szConfigDir, DEFAULT_CONFIGDIR, sizeof(szConfigDir));
1705       return szConfigDir;
1706    }
1707    if (szConfigDir[0] == '\0') {
1708       hr = p_SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL, 0, szConfigDir);
1709       if (SUCCEEDED(hr)) {
1710          bstrncat(szConfigDir, "\\Bacula", sizeof(szConfigDir));
1711       } else {
1712          bstrncpy(szConfigDir, DEFAULT_CONFIGDIR, sizeof(szConfigDir));
1713       }
1714    }
1715    return szConfigDir;
1716 #endif
1717 
1718 
1719 /*
1720  * Returns false on error
1721  *         true  on OK, with full_path set to where config file should be
1722  */
1723 bool
find_config_file(const char * config_file,char * full_path,int max_path)1724 find_config_file(const char *config_file, char *full_path, int max_path)
1725 {
1726    int file_length = strlen(config_file) + 1;
1727 
1728    /* If a full path specified, use it */
1729    if (first_path_separator(config_file) != NULL) {
1730       if (file_length > max_path) {
1731          return false;
1732       }
1733       bstrncpy(full_path, config_file, file_length);
1734       return true;
1735    }
1736 
1737    /* config_file is default file name, now find default dir */
1738    const char *config_dir = get_default_configdir();
1739    int dir_length = strlen(config_dir);
1740 
1741    if ((dir_length + 1 + file_length) > max_path) {
1742       return false;
1743    }
1744 
1745    memcpy(full_path, config_dir, dir_length + 1);
1746 
1747    if (!IsPathSeparator(full_path[dir_length - 1])) {
1748       full_path[dir_length++] = '/';
1749    }
1750 
1751    memcpy(&full_path[dir_length], config_file, file_length);
1752 
1753    return true;
1754 }
1755 
1756 /*********************************************************************
1757  *
1758  *      Free configuration resources
1759  *
1760  */
free_all_resources()1761 void CONFIG::free_all_resources()
1762 {
1763    RES *next, *res;
1764    if (m_res_head == NULL) {
1765       return;
1766    }
1767    /* Walk down chain of res_heads */
1768    for (int i=m_r_first; i<=m_r_last; i++) {
1769       if (m_res_head[i-m_r_first]) {
1770          next = m_res_head[i-m_r_first]->first;
1771          Dmsg2(500, "i=%d, next=%p\n", i, next);
1772          /* Walk down resource chain freeing them */
1773          for ( ; next; ) {
1774             res = next;
1775             next = res->res_next;
1776             free_resource(res, i);
1777          }
1778         free(m_res_head[i-m_r_first]->res_list);
1779         free(m_res_head[i-m_r_first]);
1780         m_res_head[i-m_r_first] = NULL;
1781       }
1782    }
1783 }
1784 
CONFIG()1785 CONFIG::CONFIG()
1786 :  m_cf(NULL),
1787    m_scan_error(NULL),
1788    m_err_type(0),
1789    m_res_all(NULL),
1790    m_res_all_size(0),
1791    m_encode_pass(true),
1792    m_r_first(0),
1793    m_r_last(0),
1794    m_resources(NULL),
1795    m_res_head(NULL)
1796 {
1797    m_errmsg = get_pool_memory(PM_EMSG);
1798    *m_errmsg = 0;
1799 }
1800 
~CONFIG()1801 CONFIG::~CONFIG() {
1802    free_all_resources();
1803    free_pool_memory(m_errmsg);
1804 }
1805 
encode_password(bool a)1806 void CONFIG::encode_password(bool a)
1807 {
1808    m_encode_pass = a;
1809 }
1810