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    {"Abort",         M_ABORT},
142    {"Fatal",         M_FATAL},
143    {"Error",         M_ERROR},
144    {"Warning",       M_WARNING},
145    {"Info",          M_INFO},
146    {"NotSaved",      M_NOTSAVED},
147    {"Skipped",       M_SKIPPED},
148    {"Mount",         M_MOUNT},
149    {"Terminate",     M_TERM},
150    {"Restored",      M_RESTORED},
151    {"Security",      M_SECURITY},
152    {"Alert",         M_ALERT},
153    {"VolMgmt",       M_VOLMGMT},
154    {"ErrorTerm",     M_ERROR_TERM},
155    {"All",           M_MAX+1},
156    {NULL,            0}
157 };
158 
159 
160 /*
161  * Tape Label types permitted in Pool records
162  *
163  *   tape label      label code = token
164  */
165 s_kw tapelabels[] = {
166    {"Bacula",        B_BACULA_LABEL},
167    {"ANSI",          B_ANSI_LABEL},
168    {"IBM",           B_IBM_LABEL},
169    {NULL,            0}
170 };
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  * Insert the resource in res_all into the
223  *  resource list.
224  */
insert_res(int rindex,int size)225 bool CONFIG::insert_res(int rindex, int size)
226 {
227    RES *res;
228    rblist *list = m_res_head[rindex]->res_list;
229    res = (RES *)malloc(size);
230    memcpy(res, m_res_all, size);
231    if (list->empty()) {
232       list->insert(res, res_compare);
233       m_res_head[rindex]->first = res;
234       m_res_head[rindex]->last = res;
235    } else {
236       RES *item, *prev;
237       prev = m_res_head[rindex]->last;
238       item = (RES *)list->insert(res, res_compare);
239       if (item != res) {
240          Mmsg(m_errmsg, _("Attempt to define second \"%s\" resource named \"%s\" is not permitted.\n"),
241               resources[rindex].name, ((URES *)res)->hdr.name);
242          return false;
243       }
244       prev->res_next = res;
245       m_res_head[rindex]->last = res;
246    }
247    Dmsg2(900, _("Inserted res: %s index=%d\n"), ((URES *)res)->hdr.name, rindex);
248    return true;
249 }
250 
251 /*
252  * Initialize the static structure to zeros, then
253  *  apply all the default values.
254  */
init_resource0(CONFIG * config,int type,RES_ITEM * items,int pass)255 static void init_resource0(CONFIG *config, int type, RES_ITEM *items, int pass)
256 {
257    int i;
258    int rindex = type - r_first;
259 
260    memset(config->m_res_all, 0, config->m_res_all_size);
261    res_all.hdr.rcode = type;
262    res_all.hdr.refcnt = 1;
263 
264    /* Set defaults in each item */
265    for (i=0; items[i].name; i++) {
266       Dmsg3(900, "Item=%s def=%s defval=%d\n", items[i].name,
267             (items[i].flags & ITEM_DEFAULT) ? "yes" : "no",
268             items[i].default_value);
269       if (items[i].flags & ITEM_DEFAULT && items[i].default_value != 0) {
270          if (items[i].handler == store_bit) {
271             *(uint32_t *)(items[i].value) |= items[i].code;
272          } else if (items[i].handler == store_bool) {
273             *(bool *)(items[i].value) = items[i].default_value != 0;
274          } else if (items[i].handler == store_pint32 ||
275                     items[i].handler == store_int32 ||
276                     items[i].handler == store_size32) {
277             *(uint32_t *)(items[i].value) = items[i].default_value;
278          } else if (items[i].handler == store_int64) {
279             *(int64_t *)(items[i].value) = items[i].default_value;
280          } else if (items[i].handler == store_size64) {
281             *(uint64_t *)(items[i].value) = (uint64_t)items[i].default_value;
282          } else if (items[i].handler == store_speed) {
283             *(uint64_t *)(items[i].value) = (uint64_t)items[i].default_value;
284          } else if (items[i].handler == store_time) {
285             *(utime_t *)(items[i].value) = (utime_t)items[i].default_value;
286          } else if (pass == 1 && items[i].handler == store_addresses) {
287             init_default_addresses((dlist**)items[i].value, items[i].default_value);
288          }
289       }
290       /* If this triggers, take a look at lib/parse_conf.h */
291       if (i >= MAX_RES_ITEMS) {
292          Emsg1(M_ERROR_TERM, 0, _("Too many directives in \"%s\" resource\n"), resources[rindex].name);
293       }
294    }
295 }
296 
297 /* Initialize a resouce with default values */
init_resource(CONFIG * config,uint32_t type,void * res,int size)298 bool init_resource(CONFIG *config, uint32_t type, void *res, int size)
299 {
300    RES_ITEM *items;
301    for (int i=0; resources[i].name; i++) {
302       if (resources[i].rcode == type) {
303          items = resources[i].items;
304          if (!items) {
305             return false;
306          }
307          init_resource0(config, type, items, 1);
308          memcpy(res, config->m_res_all, size);
309          return true;
310       }
311    }
312    return false;
313 }
314 
315 /*
316  * Dump each resource of type
317  */
dump_each_resource(int type,void sendit (void * sock,const char * fmt,...),void * sock)318 void dump_each_resource(int type, void sendit(void *sock, const char *fmt, ...), void *sock)
319 {
320    RES *res = NULL;
321 
322    if (type < 0) {                    /* no recursion */
323       type = -type;
324    }
325    foreach_res(res, type) {
326       dump_resource(-type, res, sendit, sock);
327    }
328 }
329 
330 
331 /* Store Messages Destination information */
store_msgs(LEX * lc,RES_ITEM * item,int index,int pass)332 void store_msgs(LEX *lc, RES_ITEM *item, int index, int pass)
333 {
334    int token;
335    char *cmd;
336    POOLMEM *dest;
337    int dest_len;
338 
339    Dmsg2(900, "store_msgs pass=%d code=%d\n", pass, item->code);
340    if (pass == 1) {
341       switch (item->code) {
342       case MD_STDOUT:
343       case MD_STDERR:
344       case MD_SYSLOG:              /* syslog */
345       case MD_CONSOLE:
346       case MD_CATALOG:
347          scan_types(lc, (MSGS *)(item->value), item->code, NULL, NULL);
348          break;
349       case MD_OPERATOR:            /* send to operator */
350       case MD_DIRECTOR:            /* send to Director */
351       case MD_MAIL:                /* mail */
352       case MD_MAIL_ON_ERROR:       /* mail if Job errors */
353       case MD_MAIL_ON_SUCCESS:     /* mail if Job succeeds */
354          if (item->code == MD_OPERATOR) {
355             cmd = res_all.res_msgs.operator_cmd;
356          } else {
357             cmd = res_all.res_msgs.mail_cmd;
358          }
359          dest = get_pool_memory(PM_MESSAGE);
360          dest[0] = 0;
361          dest_len = 0;
362          /* Pick up comma separated list of destinations */
363          for ( ;; ) {
364             token = lex_get_token(lc, T_NAME);   /* scan destination */
365             dest = check_pool_memory_size(dest, dest_len + lc->str_len + 2);
366             if (dest[0] != 0) {
367                pm_strcat(dest, " ");  /* separate multiple destinations with space */
368                dest_len++;
369             }
370             pm_strcat(dest, lc->str);
371             dest_len += lc->str_len;
372             Dmsg2(900, "store_msgs newdest=%s: dest=%s:\n", lc->str, NPRT(dest));
373             token = lex_get_token(lc, T_SKIP_EOL);
374             if (token == T_COMMA) {
375                continue;           /* get another destination */
376             }
377             if (token != T_EQUALS) {
378                scan_err1(lc, _("expected an =, got: %s"), lc->str);
379                return;
380             }
381             break;
382          }
383          Dmsg1(900, "mail_cmd=%s\n", NPRT(cmd));
384          scan_types(lc, (MSGS *)(item->value), item->code, dest, cmd);
385          free_pool_memory(dest);
386          Dmsg0(900, "done with dest codes\n");
387          break;
388 
389       case MD_FILE:                /* file */
390       case MD_APPEND:              /* append */
391          dest = get_pool_memory(PM_MESSAGE);
392          /* Pick up a single destination */
393          token = lex_get_token(lc, T_NAME);   /* scan destination */
394          pm_strcpy(dest, lc->str);
395          dest_len = lc->str_len;
396          token = lex_get_token(lc, T_SKIP_EOL);
397          Dmsg1(900, "store_msgs dest=%s:\n", NPRT(dest));
398          if (token != T_EQUALS) {
399             scan_err1(lc, _("expected an =, got: %s"), lc->str);
400             return;
401          }
402          scan_types(lc, (MSGS *)(item->value), item->code, dest, NULL);
403          free_pool_memory(dest);
404          Dmsg0(900, "done with dest codes\n");
405          break;
406 
407       default:
408          scan_err1(lc, _("Unknown item code: %d\n"), item->code);
409          return;
410       }
411    }
412    scan_to_eol(lc);
413    set_bit(index, res_all.hdr.item_present);
414    Dmsg0(900, "Done store_msgs\n");
415 }
416 
417 /*
418  * Scan for message types and add them to the message
419  * destination. The basic job here is to connect message types
420  *  (WARNING, ERROR, FATAL, INFO, ...) with an appropriate
421  *  destination (MAIL, FILE, OPERATOR, ...)
422  */
scan_types(LEX * lc,MSGS * msg,int dest_code,char * where,char * cmd)423 static void scan_types(LEX *lc, MSGS *msg, int dest_code, char *where, char *cmd)
424 {
425    int i;
426    bool found, is_not;
427    int msg_type = 0;
428    char *str;
429 
430    for ( ;; ) {
431       lex_get_token(lc, T_NAME);            /* expect at least one type */
432       found = false;
433       if (lc->str[0] == '!') {
434          is_not = true;
435          str = &lc->str[1];
436       } else {
437          is_not = false;
438          str = &lc->str[0];
439       }
440       for (i=0; msg_types[i].name; i++) {
441          if (strcasecmp(str, msg_types[i].name) == 0) {
442             msg_type = msg_types[i].token;
443             found = true;
444             break;
445          }
446       }
447       if (!found) {
448          scan_err1(lc, _("message type: %s not found"), str);
449          return;
450       }
451 
452       if (msg_type == M_MAX+1) {         /* all? */
453          for (i=2; i<=M_MAX; i++) {      /* yes set all types except Debug and Saved */
454             add_msg_dest(msg, dest_code, msg_types[i].token, where, cmd);
455          }
456       } else if (is_not) {
457          rem_msg_dest(msg, dest_code, msg_type, where);
458       } else {
459          add_msg_dest(msg, dest_code, msg_type, where, cmd);
460       }
461       if (lc->ch != ',') {
462          break;
463       }
464       Dmsg0(900, "call lex_get_token() to eat comma\n");
465       lex_get_token(lc, T_ALL);          /* eat comma */
466    }
467    Dmsg0(900, "Done scan_types()\n");
468 }
469 
470 
471 /*
472  * This routine is ONLY for resource names
473  *  Store a name at specified address.
474  */
store_name(LEX * lc,RES_ITEM * item,int index,int pass)475 void store_name(LEX *lc, RES_ITEM *item, int index, int pass)
476 {
477    POOLMEM *msg = get_pool_memory(PM_EMSG);
478 
479    lex_get_token(lc, T_NAME);
480    if (!is_name_valid(lc->str, &msg)) {
481       scan_err1(lc, "%s\n", msg);
482       return;
483    }
484    free_pool_memory(msg);
485    /* Store the name both pass 1 and pass 2 */
486    if (*(item->value)) {
487       scan_err5(lc, _("Attempt to redefine \"%s\" from \"%s\" to \"%s\" referenced on line %d : %s\n"),
488          item->name, *(item->value), lc->str, lc->line_no, lc->line);
489       return;
490    }
491    *(item->value) = bstrdup(lc->str);
492    scan_to_eol(lc);
493    set_bit(index, res_all.hdr.item_present);
494 }
495 
496 
497 /*
498  * Store a name string at specified address
499  * A name string is limited to MAX_RES_NAME_LENGTH
500  */
store_strname(LEX * lc,RES_ITEM * item,int index,int pass)501 void store_strname(LEX *lc, RES_ITEM *item, int index, int pass)
502 {
503    lex_get_token(lc, T_NAME);
504    /* Store the name */
505    if (pass == 1) {
506       if (*(item->value)) {
507          scan_err5(lc, _("Attempt to redefine \"%s\" from \"%s\" to \"%s\" referenced on line %d : %s\n"),
508             item->name, *(item->value), lc->str, lc->line_no, lc->line);
509          return;
510       }
511       *(item->value) = bstrdup(lc->str);
512    }
513    scan_to_eol(lc);
514    set_bit(index, res_all.hdr.item_present);
515 }
516 
517 /* Store a string at specified address */
store_str(LEX * lc,RES_ITEM * item,int index,int pass)518 void store_str(LEX *lc, RES_ITEM *item, int index, int pass)
519 {
520    lex_get_token(lc, T_STRING);
521    if (pass == 1) {
522       if (*(item->value) && (item->flags & ITEM_ALLOW_DUPS)) {
523          free(*(item->value));
524          *(item->value) = NULL;
525       }
526       if (*(item->value)) {
527          scan_err5(lc, _("Attempt to redefine \"%s\" from \"%s\" to \"%s\" referenced on line %d : %s\n"),
528             item->name, *(item->value), lc->str, lc->line_no, lc->line);
529          return;
530       }
531       *(item->value) = bstrdup(lc->str);
532    }
533    scan_to_eol(lc);
534    set_bit(index, res_all.hdr.item_present);
535 }
536 
537 /*
538  * Store a directory name at specified address. Note, we do
539  *   shell expansion except if the string begins with a vertical
540  *   bar (i.e. it will likely be passed to the shell later).
541  */
store_dir(LEX * lc,RES_ITEM * item,int index,int pass)542 void store_dir(LEX *lc, RES_ITEM *item, int index, int pass)
543 {
544    lex_get_token(lc, T_STRING);
545    if (pass == 1) {
546       if (lc->str[0] != '|') {
547          do_shell_expansion(lc->str, sizeof_pool_memory(lc->str));
548       }
549 #ifdef STANDARDIZED_DIRECTORY_USAGE
550       // TODO ASX we should store all directory without the ending slash to
551       // avoid the need of testing its presence
552       int len=strlen(lc->str);
553       if (len>0 && IsPathSeparator(lc->str[len-1])) {
554          lc->str[len-1]='\0';
555       }
556 #endif
557       if (*(item->value)) {
558          scan_err5(lc, _("Attempt to redefine \"%s\" from \"%s\" to \"%s\" referenced on line %d : %s\n"),
559             item->name, *(item->value), lc->str, lc->line_no, lc->line);
560          return;
561       }
562       *(item->value) = bstrdup(lc->str);
563    }
564    scan_to_eol(lc);
565    set_bit(index, res_all.hdr.item_present);
566 }
567 
568 
569 /* Store a password specified address in MD5 coding */
store_password(LEX * lc,RES_ITEM * item,int index,int pass)570 void store_password(LEX *lc, RES_ITEM *item, int index, int pass)
571 {
572    unsigned int i, j;
573    struct MD5Context md5c;
574    unsigned char digest[CRYPTO_DIGEST_MD5_SIZE];
575    char sig[100];
576 
577    if (lc->options & LOPT_NO_MD5) {
578       store_str(lc, item, index, pass);
579 
580    } else {
581       lex_get_token(lc, T_STRING);
582       if (pass == 1) {
583          MD5Init(&md5c);
584          MD5Update(&md5c, (unsigned char *) (lc->str), lc->str_len);
585          MD5Final(digest, &md5c);
586          for (i = j = 0; i < sizeof(digest); i++) {
587             sprintf(&sig[j], "%02x", digest[i]);
588             j += 2;
589          }
590          if (*(item->value)) {
591             scan_err5(lc, _("Attempt to redefine \"%s\" from \"%s\" to \"%s\" referenced on line %d : %s\n"),
592                item->name, *(item->value), lc->str, lc->line_no, lc->line);
593             return;
594          }
595          *(item->value) = bstrdup(sig);
596       }
597       scan_to_eol(lc);
598       set_bit(index, res_all.hdr.item_present);
599    }
600 }
601 
602 
603 /* Store a resource at specified address.
604  * If we are in pass 2, do a lookup of the
605  * resource.
606  */
store_res(LEX * lc,RES_ITEM * item,int index,int pass)607 void store_res(LEX *lc, RES_ITEM *item, int index, int pass)
608 {
609    RES *res;
610 
611    lex_get_token(lc, T_NAME);
612    if (pass == 2) {
613       res = GetResWithName(item->code, lc->str);
614       if (res == NULL) {
615          scan_err3(lc, _("Could not find config Resource \"%s\" referenced on line %d : %s\n"),
616             lc->str, lc->line_no, lc->line);
617          return;
618       }
619       if (*(item->value)) {
620          scan_err3(lc, _("Attempt to redefine resource \"%s\" referenced on line %d : %s\n"),
621             item->name, lc->line_no, lc->line);
622          return;
623       }
624       *(item->value) = (char *)res;
625    }
626    scan_to_eol(lc);
627    set_bit(index, res_all.hdr.item_present);
628 }
629 
630 /*
631  * Store a resource pointer in an alist. default_value indicates how many
632  *   times this routine can be called -- i.e. how many alists
633  *   there are.
634  * If we are in pass 2, do a lookup of the
635  *   resource.
636  */
store_alist_res(LEX * lc,RES_ITEM * item,int index,int pass)637 void store_alist_res(LEX *lc, RES_ITEM *item, int index, int pass)
638 {
639    RES *res;
640    int count = item->default_value;
641    int i = 0;
642    alist *list;
643 
644    if (pass == 2) {
645       if (count == 0) {               /* always store in item->value */
646          i = 0;
647          if ((item->value)[i] == NULL) {
648             list = New(alist(10, not_owned_by_alist));
649          } else {
650             list = (alist *)(item->value)[i];
651          }
652       } else {
653          /* Find empty place to store this directive */
654          while ((item->value)[i] != NULL && i++ < count) { }
655          if (i >= count) {
656             scan_err4(lc, _("Too many %s directives. Max. is %d. line %d: %s\n"),
657                lc->str, count, lc->line_no, lc->line);
658             return;
659          }
660          list = New(alist(10, not_owned_by_alist));
661       }
662 
663       for (;;) {
664          lex_get_token(lc, T_NAME);   /* scan next item */
665          res = GetResWithName(item->code, lc->str);
666          if (res == NULL) {
667             scan_err3(lc, _("Could not find config Resource \"%s\" referenced on line %d : %s\n"),
668                lc->str, lc->line_no, lc->line);
669             return;
670          }
671          Dmsg5(900, "Append %p to alist %p size=%d i=%d %s\n",
672                res, list, list->size(), i, item->name);
673          list->append(res);
674          (item->value)[i] = (char *)list;
675          if (lc->ch != ',') {         /* if no other item follows */
676             if (!lex_check_eol(lc)) {
677                /* found garbage at the end of the line */
678                scan_err3(lc, _("Found unexpected characters resource list in Directive \"%s\" at the end of line %d : %s\n"),
679                   item->name, lc->line_no, lc->line);
680             }
681             break;                    /* get out */
682          }
683          lex_get_token(lc, T_ALL);    /* eat comma */
684       }
685    }
686    scan_to_eol(lc);
687    set_bit(index, res_all.hdr.item_present);
688 }
689 
690 
691 /*
692  * Store a string in an alist.
693  */
store_alist_str(LEX * lc,RES_ITEM * item,int index,int pass)694 void store_alist_str(LEX *lc, RES_ITEM *item, int index, int pass)
695 {
696    alist *list;
697 
698    if (pass == 2) {
699       if (*(item->value) == NULL) {
700          list = New(alist(10, owned_by_alist));
701          *(item->value) = (char *)list;
702       } else {
703          list = (alist *)(*(item->value));
704       }
705       for (;;) {
706          lex_get_token(lc, T_STRING);   /* scan next item */
707          Dmsg4(900, "Append %s to alist 0x%p size=%d %s\n",
708             lc->str, list, list->size(), item->name);
709          list->append(bstrdup(lc->str));
710          if (lc->ch != ',') {         /* if no other item follows */
711             if (!lex_check_eol(lc)) {
712                /* found garbage at the end of the line */
713                scan_err3(lc, _("Found unexpected characters in resource list in Directive \"%s\" at the end of line %d : %s\n"),
714                   item->name, lc->line_no, lc->line);
715             }
716             break;                    /* get out */
717          }
718          lex_get_token(lc, T_ALL);    /* eat comma */
719       }
720    }
721    scan_to_eol(lc);
722    set_bit(index, res_all.hdr.item_present);
723 }
724 
725 
726 
727 /*
728  * Store default values for Resource from xxxDefs
729  * If we are in pass 2, do a lookup of the
730  * resource and store everything not explicitly set
731  * in main resource.
732  *
733  * Note, here item points to the main resource (e.g. Job, not
734  *  the jobdefs, which we look up).
735  */
store_defs(LEX * lc,RES_ITEM * item,int index,int pass)736 void store_defs(LEX *lc, RES_ITEM *item, int index, int pass)
737 {
738    RES *res;
739 
740    lex_get_token(lc, T_NAME);
741    if (pass == 2) {
742      Dmsg2(900, "Code=%d name=%s\n", item->code, lc->str);
743      res = GetResWithName(item->code, lc->str);
744      if (res == NULL) {
745         scan_err3(lc, _("Missing config Resource \"%s\" referenced on line %d : %s\n"),
746            lc->str, lc->line_no, lc->line);
747         return;
748      }
749    }
750    scan_to_eol(lc);
751 }
752 
753 
754 
755 /* Store an integer at specified address */
store_int32(LEX * lc,RES_ITEM * item,int index,int pass)756 void store_int32(LEX *lc, RES_ITEM *item, int index, int pass)
757 {
758    lex_get_token(lc, T_INT32);
759    *(uint32_t *)(item->value) = lc->int32_val;
760    scan_to_eol(lc);
761    set_bit(index, res_all.hdr.item_present);
762 }
763 
764 /* Store a positive integer at specified address */
store_pint32(LEX * lc,RES_ITEM * item,int index,int pass)765 void store_pint32(LEX *lc, RES_ITEM *item, int index, int pass)
766 {
767    lex_get_token(lc, T_PINT32);
768    *(uint32_t *)(item->value) = lc->pint32_val;
769    scan_to_eol(lc);
770    set_bit(index, res_all.hdr.item_present);
771 }
772 
773 
774 /* Store an 64 bit integer at specified address */
store_int64(LEX * lc,RES_ITEM * item,int index,int pass)775 void store_int64(LEX *lc, RES_ITEM *item, int index, int pass)
776 {
777    lex_get_token(lc, T_INT64);
778    *(int64_t *)(item->value) = lc->int64_val;
779    scan_to_eol(lc);
780    set_bit(index, res_all.hdr.item_present);
781 }
782 
783 enum store_unit_type {
784    STORE_SIZE,
785    STORE_SPEED
786 } ;
787 
788 /*
789  * This routine stores either a 32 or a 64 bit value (size32)
790  *  and either a size (in bytes) or a speed (bytes per second).
791  */
store_int_unit(LEX * lc,RES_ITEM * item,int index,int pass,bool size32,enum store_unit_type type)792 static void store_int_unit(LEX *lc, RES_ITEM *item, int index, int pass,
793                            bool size32, enum store_unit_type type)
794 {
795    int token;
796    uint64_t uvalue;
797    char bsize[500];
798 
799    Dmsg0(900, "Enter store_unit\n");
800    token = lex_get_token(lc, T_SKIP_EOL);
801    errno = 0;
802    switch (token) {
803    case T_NUMBER:
804    case T_IDENTIFIER:
805    case T_UNQUOTED_STRING:
806       bstrncpy(bsize, lc->str, sizeof(bsize));  /* save first part */
807       /* if terminated by space, scan and get modifier */
808       while (lc->ch == ' ') {
809          token = lex_get_token(lc, T_ALL);
810          switch (token) {
811          case T_NUMBER:
812          case T_IDENTIFIER:
813          case T_UNQUOTED_STRING:
814             bstrncat(bsize, lc->str, sizeof(bsize));
815             break;
816          }
817       }
818       if (type == STORE_SIZE) {
819          if (!size_to_uint64(bsize, strlen(bsize), &uvalue)) {
820             scan_err1(lc, _("expected a size number, got: %s"), lc->str);
821             return;
822          }
823       } else {
824          if (!speed_to_uint64(bsize, strlen(bsize), &uvalue)) {
825             scan_err1(lc, _("expected a speed number, got: %s"), lc->str);
826             return;
827          }
828       }
829       if (size32) {
830          *(uint32_t *)(item->value) = (uint32_t)uvalue;
831       } else {
832          *(uint64_t *)(item->value) = uvalue;
833       }
834       break;
835    default:
836       scan_err2(lc, _("expected a %s, got: %s"),
837                 (type == STORE_SIZE)?_("size"):_("speed"), lc->str);
838       return;
839    }
840    if (token != T_EOL) {
841       scan_to_eol(lc);
842    }
843    set_bit(index, res_all.hdr.item_present);
844    Dmsg0(900, "Leave store_unit\n");
845 }
846 
847 /* Store a size in bytes */
store_size32(LEX * lc,RES_ITEM * item,int index,int pass)848 void store_size32(LEX *lc, RES_ITEM *item, int index, int pass)
849 {
850    store_int_unit(lc, item, index, pass, true /* 32 bit */, STORE_SIZE);
851 }
852 
853 /* Store a size in bytes */
store_size64(LEX * lc,RES_ITEM * item,int index,int pass)854 void store_size64(LEX *lc, RES_ITEM *item, int index, int pass)
855 {
856    store_int_unit(lc, item, index, pass, false /* not 32 bit */, STORE_SIZE);
857 }
858 
859 /* Store a speed in bytes/s */
store_speed(LEX * lc,RES_ITEM * item,int index,int pass)860 void store_speed(LEX *lc, RES_ITEM *item, int index, int pass)
861 {
862    store_int_unit(lc, item, index, pass, false /* 64 bit */, STORE_SPEED);
863 }
864 
865 /* Store a time period in seconds */
store_time(LEX * lc,RES_ITEM * item,int index,int pass)866 void store_time(LEX *lc, RES_ITEM *item, int index, int pass)
867 {
868    int token;
869    utime_t utime;
870    char period[500];
871 
872    token = lex_get_token(lc, T_SKIP_EOL);
873    errno = 0;
874    switch (token) {
875    case T_NUMBER:
876    case T_IDENTIFIER:
877    case T_UNQUOTED_STRING:
878       bstrncpy(period, lc->str, sizeof(period));  /* get first part */
879       /* if terminated by space, scan and get modifier */
880       while (lc->ch == ' ') {
881          token = lex_get_token(lc, T_ALL);
882          switch (token) {
883          case T_NUMBER:
884          case T_IDENTIFIER:
885          case T_UNQUOTED_STRING:
886             bstrncat(period, lc->str, sizeof(period));
887             break;
888          }
889       }
890       if (!duration_to_utime(period, &utime)) {
891          scan_err1(lc, _("expected a time period, got: %s"), period);
892          return;
893       }
894       *(utime_t *)(item->value) = utime;
895       break;
896    default:
897       scan_err1(lc, _("expected a time period, got: %s"), lc->str);
898       return;
899    }
900    if (token != T_EOL) {
901       scan_to_eol(lc);
902    }
903    set_bit(index, res_all.hdr.item_present);
904 }
905 
906 
907 /* Store a yes/no in a bit field */
store_bit(LEX * lc,RES_ITEM * item,int index,int pass)908 void store_bit(LEX *lc, RES_ITEM *item, int index, int pass)
909 {
910    lex_get_token(lc, T_NAME);
911    if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
912       *(uint32_t *)(item->value) |= item->code;
913    } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
914       *(uint32_t *)(item->value) &= ~(item->code);
915    } else {
916       scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
917       return;
918    }
919    scan_to_eol(lc);
920    set_bit(index, res_all.hdr.item_present);
921 }
922 
923 /* Store a bool in a bit field */
store_bool(LEX * lc,RES_ITEM * item,int index,int pass)924 void store_bool(LEX *lc, RES_ITEM *item, int index, int pass)
925 {
926    lex_get_token(lc, T_NAME);
927    if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
928       *(bool *)(item->value) = true;
929    } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
930       *(bool *)(item->value) = false;
931    } else {
932       scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
933       return;
934    }
935    scan_to_eol(lc);
936    set_bit(index, res_all.hdr.item_present);
937 }
938 
939 
940 /*
941  * Store Tape Label Type (Bacula, ANSI, IBM)
942  *
943  */
store_label(LEX * lc,RES_ITEM * item,int index,int pass)944 void store_label(LEX *lc, RES_ITEM *item, int index, int pass)
945 {
946    int i;
947 
948    lex_get_token(lc, T_NAME);
949    /* Store the label pass 2 so that type is defined */
950    for (i=0; tapelabels[i].name; i++) {
951       if (strcasecmp(lc->str, tapelabels[i].name) == 0) {
952          *(uint32_t *)(item->value) = tapelabels[i].token;
953          i = 0;
954          break;
955       }
956    }
957    if (i != 0) {
958       scan_err1(lc, _("Expected a Tape Label keyword, got: %s"), lc->str);
959       return;
960    }
961    scan_to_eol(lc);
962    set_bit(index, res_all.hdr.item_present);
963 }
964 
965 /*
966  * Store Statistics Type (CSV, Graphite - only supported)
967  */
store_coll_type(LEX * lc,RES_ITEM * item,int index,int pass)968 void store_coll_type(LEX *lc, RES_ITEM *item, int index, int pass)
969 {
970    int i;
971 
972    lex_get_token(lc, T_NAME);
973    /* Store the type both pass 1 and pass 2 */
974    for (i = 0; collectortypes[i].type_name; i++) {
975       if (strcasecmp(lc->str, collectortypes[i].type_name) == 0) {
976          *(int32_t *)(item->value) = collectortypes[i].coll_type;
977          i = 0;
978          break;
979       }
980    }
981    if (i != 0) {
982       scan_err1(lc, _("Expected a Statistics backend type keyword, got: %s"), lc->str);
983    }
984    scan_to_eol(lc);
985    set_bit(index, res_all.hdr.item_present);
986 }
987 
988 /* Parser state */
989 enum parse_state {
990    p_none,
991    p_resource
992 };
993 
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)994 void CONFIG::init(
995    const char *cf,
996    LEX_ERROR_HANDLER *scan_error,
997    int32_t err_type,
998    void *vres_all,
999    int32_t res_all_size,
1000    int32_t r_first,
1001    int32_t r_last,
1002    RES_TABLE *resources,
1003    RES_HEAD ***res_head)
1004 {
1005    m_cf = cf;
1006    m_scan_error = scan_error;
1007    m_err_type = err_type;
1008    m_res_all = vres_all;
1009    m_res_all_size = res_all_size;
1010    m_r_first = r_first;
1011    m_r_last = r_last;
1012    m_resources = resources;
1013    init_res_head(res_head, r_first, r_last);
1014    m_res_head = *res_head;
1015 }
1016 
1017 /*********************************************************************
1018  *
1019  * Parse configuration file
1020  *
1021  * Return 0 if reading failed, 1 otherwise
1022  *  Note, the default behavior unless you have set an alternate
1023  *  scan_error handler is to die on an error.
1024  */
parse_config()1025 bool CONFIG::parse_config()
1026 {
1027    LEX *lc = NULL;
1028    int token, i, pass;
1029    int res_type = 0;
1030    enum parse_state state = p_none;
1031    RES_ITEM *items = NULL;
1032    int level = 0;
1033    static bool first = true;
1034    int errstat;
1035    const char *cf = m_cf;
1036    LEX_ERROR_HANDLER *scan_error = m_scan_error;
1037    int err_type = m_err_type;
1038    //HPKT hpkt;
1039 
1040    if (first && (errstat=rwl_init(&res_lock)) != 0) {
1041       berrno be;
1042       Jmsg1(NULL, M_ABORT, 0, _("Unable to initialize resource lock. ERR=%s\n"),
1043             be.bstrerror(errstat));
1044    }
1045    first = false;
1046 
1047    char *full_path = (char *)alloca(MAX_PATH + 1);
1048 
1049    if (!find_config_file(cf, full_path, MAX_PATH +1)) {
1050       Jmsg0(NULL, M_ABORT, 0, _("Config filename too long.\n"));
1051    }
1052    cf = full_path;
1053 
1054    /* Make two passes. The first builds the name symbol table,
1055     * and the second picks up the items.
1056     */
1057    Dmsg0(900, "Enter parse_config()\n");
1058    for (pass=1; pass <= 2; pass++) {
1059       Dmsg1(900, "parse_config pass %d\n", pass);
1060       if ((lc = lex_open_file(lc, cf, scan_error)) == NULL) {
1061          berrno be;
1062          /* We must create a lex packet to print the error */
1063          lc = (LEX *)malloc(sizeof(LEX));
1064          memset(lc, 0, sizeof(LEX));
1065          lc->str = get_memory(5000);
1066          if (scan_error) {
1067             lc->scan_error = scan_error;
1068          } else {
1069             lex_set_default_error_handler(lc);
1070          }
1071          lex_set_error_handler_error_type(lc, err_type) ;
1072          pm_strcpy(lc->str, cf);
1073          lc->fname = lc->str;
1074          scan_err2(lc, _("Cannot open config file \"%s\": %s\n"),
1075             lc->str, be.bstrerror());
1076          free_pool_memory(lc->str);
1077          free(lc);
1078          return 0;
1079       }
1080       if (!m_encode_pass) {
1081          lex_store_clear_passwords(lc);
1082       }
1083       lex_set_error_handler_error_type(lc, err_type) ;
1084       while ((token=lex_get_token(lc, T_ALL)) != T_EOF) {
1085          Dmsg3(900, "parse state=%d pass=%d got token=%s\n", state, pass,
1086               lex_tok_to_str(token));
1087          switch (state) {
1088          case p_none:
1089             if (token == T_EOL) {
1090                break;
1091             } else if (token == T_UTF8_BOM) {
1092                /* We can assume the file is UTF-8 as we have seen a UTF-8 BOM */
1093                break;
1094             } else if (token == T_UTF16_BOM) {
1095                scan_err0(lc, _("Currently we cannot handle UTF-16 source files. "
1096                    "Please convert the conf file to UTF-8\n"));
1097                goto bail_out;
1098             } else if (token != T_IDENTIFIER) {
1099                scan_err1(lc, _("Expected a Resource name identifier, got: %s"), lc->str);
1100                goto bail_out;
1101             }
1102             for (i=0; resources[i].name; i++) {
1103                if (strcasecmp(resources[i].name, lc->str) == 0) {
1104                   items = resources[i].items;
1105                   if (!items) {
1106                      break;
1107                   }
1108                   state = p_resource;
1109                   res_type = resources[i].rcode;
1110                   init_resource0(this, res_type, items, pass);
1111                   break;
1112                }
1113             }
1114             if (state == p_none) {
1115                scan_err1(lc, _("expected resource name, got: %s"), lc->str);
1116                goto bail_out;
1117             }
1118             break;
1119          case p_resource:
1120             switch (token) {
1121             case T_BOB:
1122                level++;
1123                break;
1124             case T_IDENTIFIER:
1125                if (level != 1) {
1126                   scan_err1(lc, _("not in resource definition: %s"), lc->str);
1127                   goto bail_out;
1128                }
1129                for (i=0; items[i].name; i++) {
1130                   //hpkt.pass = pass;
1131                   //hpkt.ritem = &items[i];
1132                   //hpkt.edbuf = NULL;
1133                   //hpkt.index = i;
1134                   //hpkt.lc = lc;
1135                   //hpkt.hfunc = HF_STORE;
1136                   if (strcasecmp(items[i].name, lc->str) == 0) {
1137                      /* If the ITEM_NO_EQUALS flag is set we do NOT
1138                       *   scan for = after the keyword  */
1139                      if (!(items[i].flags & ITEM_NO_EQUALS)) {
1140                         token = lex_get_token(lc, T_SKIP_EOL);
1141                         Dmsg1 (900, "in T_IDENT got token=%s\n", lex_tok_to_str(token));
1142                         if (token != T_EQUALS) {
1143                            scan_err1(lc, _("expected an equals, got: %s"), lc->str);
1144                            goto bail_out;
1145                         }
1146                      }
1147                      Dmsg1(800, "calling handler for %s\n", items[i].name);
1148                      /* Call item handler */
1149                      items[i].handler(lc, &items[i], i, pass);
1150                      i = -1;
1151                      break;
1152                   }
1153                }
1154                if (i >= 0) {
1155                   Dmsg2(900, "level=%d id=%s\n", level, lc->str);
1156                   Dmsg1(900, "Keyword = %s\n", lc->str);
1157                   scan_err1(lc, _("Keyword \"%s\" not permitted in this resource.\n"
1158                      "Perhaps you left the trailing brace off of the previous resource."), lc->str);
1159                   goto bail_out;
1160                }
1161                break;
1162 
1163             case T_EOB:
1164                level--;
1165                state = p_none;
1166                Dmsg0(900, "T_EOB => define new resource\n");
1167                if (res_all.hdr.name == NULL) {
1168                   scan_err0(lc, _("Name not specified for resource"));
1169                   goto bail_out;
1170                }
1171                if (!save_resource(this, res_type, items, pass)) {  /* save resource */
1172                   scan_err1(lc, "%s", m_errmsg);
1173                   goto bail_out;
1174                }
1175                break;
1176 
1177             case T_EOL:
1178                break;
1179 
1180             default:
1181                scan_err2(lc, _("unexpected token %d %s in resource definition"),
1182                   token, lex_tok_to_str(token));
1183                goto bail_out;
1184             }
1185             break;
1186          default:
1187             scan_err1(lc, _("Unknown parser state %d\n"), state);
1188             goto bail_out;
1189          }
1190       }
1191       if (state != p_none) {
1192          scan_err0(lc, _("End of conf file reached with unclosed resource."));
1193          goto bail_out;
1194       }
1195       if (chk_dbglvl(900) && pass == 2) {
1196          int i;
1197          for (i=m_r_first; i<=m_r_last; i++) {
1198             dump_each_resource(i, prtmsg, NULL);
1199          }
1200       }
1201       lc = lex_close_file(lc);
1202    }
1203    Dmsg0(900, "Leave parse_config()\n");
1204    return 1;
1205 bail_out:
1206    if (lc) {
1207       lc = lex_close_file(lc);
1208    }
1209    return 0;
1210 }
1211 
get_default_configdir()1212 const char *get_default_configdir()
1213 {
1214    return SYSCONFDIR;
1215 }
1216 
1217 #ifdef xxx_not_used
1218    HRESULT hr;
1219    static char szConfigDir[MAX_PATH + 1] = { 0 };
1220    if (!p_SHGetFolderPath) {
1221       bstrncpy(szConfigDir, DEFAULT_CONFIGDIR, sizeof(szConfigDir));
1222       return szConfigDir;
1223    }
1224    if (szConfigDir[0] == '\0') {
1225       hr = p_SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL, 0, szConfigDir);
1226       if (SUCCEEDED(hr)) {
1227          bstrncat(szConfigDir, "\\Bacula", sizeof(szConfigDir));
1228       } else {
1229          bstrncpy(szConfigDir, DEFAULT_CONFIGDIR, sizeof(szConfigDir));
1230       }
1231    }
1232    return szConfigDir;
1233 #endif
1234 
1235 
1236 /*
1237  * Returns false on error
1238  *         true  on OK, with full_path set to where config file should be
1239  */
1240 bool
find_config_file(const char * config_file,char * full_path,int max_path)1241 find_config_file(const char *config_file, char *full_path, int max_path)
1242 {
1243    int file_length = strlen(config_file) + 1;
1244 
1245    /* If a full path specified, use it */
1246    if (first_path_separator(config_file) != NULL) {
1247       if (file_length > max_path) {
1248          return false;
1249       }
1250       bstrncpy(full_path, config_file, file_length);
1251       return true;
1252    }
1253 
1254    /* config_file is default file name, now find default dir */
1255    const char *config_dir = get_default_configdir();
1256    int dir_length = strlen(config_dir);
1257 
1258    if ((dir_length + 1 + file_length) > max_path) {
1259       return false;
1260    }
1261 
1262    memcpy(full_path, config_dir, dir_length + 1);
1263 
1264    if (!IsPathSeparator(full_path[dir_length - 1])) {
1265       full_path[dir_length++] = '/';
1266    }
1267 
1268    memcpy(&full_path[dir_length], config_file, file_length);
1269 
1270    return true;
1271 }
1272 
1273 /*********************************************************************
1274  *
1275  *      Free configuration resources
1276  *
1277  */
free_all_resources()1278 void CONFIG::free_all_resources()
1279 {
1280    RES *next, *res;
1281    if (m_res_head == NULL) {
1282       return;
1283    }
1284    /* Walk down chain of res_heads */
1285    for (int i=m_r_first; i<=m_r_last; i++) {
1286       if (m_res_head[i-m_r_first]) {
1287          next = m_res_head[i-m_r_first]->first;
1288          Dmsg2(500, "i=%d, next=%p\n", i, next);
1289          /* Walk down resource chain freeing them */
1290          for ( ; next; ) {
1291             res = next;
1292             next = res->res_next;
1293             free_resource(res, i);
1294          }
1295         free(m_res_head[i-m_r_first]->res_list);
1296         free(m_res_head[i-m_r_first]);
1297         m_res_head[i-m_r_first] = NULL;
1298       }
1299    }
1300 }
1301 
CONFIG()1302 CONFIG::CONFIG()
1303 :  m_cf(NULL),
1304    m_scan_error(NULL),
1305    m_err_type(0),
1306    m_res_all(NULL),
1307    m_res_all_size(0),
1308    m_encode_pass(true),
1309    m_r_first(0),
1310    m_r_last(0),
1311    m_resources(NULL),
1312    m_res_head(NULL)
1313 {
1314    m_errmsg = get_pool_memory(PM_EMSG);
1315    *m_errmsg = 0;
1316 }
1317 
~CONFIG()1318 CONFIG::~CONFIG() {
1319    free_all_resources();
1320    free_pool_memory(m_errmsg);
1321 }
1322 
encode_password(bool a)1323 void CONFIG::encode_password(bool a)
1324 {
1325    m_encode_pass = a;
1326 }
1327