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  *   Main configuration file parser for Bacula File Daemon (Client)
21  *    some parts may be split into separate files such as
22  *    the schedule configuration (sch_config.c).
23  *
24  *   Note, the configuration file parser consists of three parts
25  *
26  *   1. The generic lexical scanner in lib/lex.c and lib/lex.h
27  *
28  *   2. The generic config  scanner in lib/parse_config.c and
29  *      lib/parse_config.h.
30  *      These files contain the parser code, some utility
31  *      routines, and the common store routines (name, int,
32  *      string).
33  *
34  *   3. The daemon specific file, which contains the Resource
35  *      definitions as well as any specific store routines
36  *      for the resource records.
37  *
38  *     Kern Sibbald, September MM
39  */
40 
41 #include "bacula.h"
42 #include "filed.h"
43 
44 /* Define the first and last resource ID record
45  * types. Note, these should be unique for each
46  * daemon though not a requirement.
47  */
48 int32_t r_first = R_FIRST;
49 int32_t r_last  = R_LAST;
50 RES_HEAD **res_head;
51 
52 
53 /* Forward referenced subroutines */
54 
55 
56 /* We build the current resource here as we are
57  * scanning the resource configuration definition,
58  * then move it to allocated memory when the resource
59  * scan is complete.
60  */
61 #if defined(_MSC_VER)
62 extern "C" { // work around visual compiler mangling variables
63    URES res_all;
64 }
65 #else
66 URES res_all;
67 #endif
68 int32_t res_all_size = sizeof(res_all);
69 
70 /* Definition of records permitted within each
71  * resource with the routine to process the record
72  * information.
73  */
74 
75 /* Client or File daemon "Global" resources */
76 static RES_ITEM cli_items[] = {
77    {"Name",        store_name,  ITEM(res_client.hdr.name), 0, ITEM_REQUIRED, 0},
78    {"Description", store_str,   ITEM(res_client.hdr.desc), 0, 0, 0},
79    {"FdPort",      store_addresses_port,    ITEM(res_client.FDaddrs),  0, ITEM_DEFAULT, 9102},
80    {"FdAddress",   store_addresses_address, ITEM(res_client.FDaddrs),  0, ITEM_DEFAULT, 9102},
81    {"FdAddresses", store_addresses,         ITEM(res_client.FDaddrs),  0, ITEM_DEFAULT, 9102},
82    {"FdSourceAddress", store_addresses_address, ITEM(res_client.FDsrc_addr),  0, ITEM_DEFAULT, 0},
83 
84    {"WorkingDirectory",  store_dir, ITEM(res_client.working_directory), 0, ITEM_REQUIRED, 0},
85    {"PidDirectory",  store_dir,     ITEM(res_client.pid_directory),     0, ITEM_REQUIRED, 0},
86    {"SubsysDirectory",  store_dir,  ITEM(res_client.subsys_directory),  0, 0, 0},
87    {"PluginDirectory",  store_dir,  ITEM(res_client.plugin_directory),  0, 0, 0},
88    {"SnapshotCommand",  store_str,  ITEM(res_client.snapshot_command), 0, 0, 0},
89    {"ScriptsDirectory", store_dir,  ITEM(res_client.scripts_directory),  0, 0, 0},
90    {"MaximumConcurrentJobs", store_pint32,  ITEM(res_client.MaxConcurrentJobs), 0, ITEM_DEFAULT, 20},
91    {"Messages",      store_res, ITEM(res_client.messages), R_MSGS, 0, 0},
92    {"SdConnectTimeout", store_time,ITEM(res_client.SDConnectTimeout), 0, ITEM_DEFAULT, 60 * 30},
93    {"HeartbeatInterval", store_time, ITEM(res_client.heartbeat_interval), 0, ITEM_DEFAULT, 5 * 60},
94    {"MaximumNetworkBufferSize", store_pint32, ITEM(res_client.max_network_buffer_size), 0, 0, 0},
95 #ifdef DATA_ENCRYPTION
96    {"PkiSignatures",         store_bool,    ITEM(res_client.pki_sign), 0, ITEM_DEFAULT, 0},
97    {"PkiEncryption",         store_bool,    ITEM(res_client.pki_encrypt), 0, ITEM_DEFAULT, 0},
98    {"PkiKeyPair",            store_dir,         ITEM(res_client.pki_keypair_file), 0, 0, 0},
99    {"PkiSigner",             store_alist_str,   ITEM(res_client.pki_signing_key_files), 0, 0, 0},
100    {"PkiMasterKey",          store_alist_str,   ITEM(res_client.pki_master_key_files), 0, 0, 0},
101    {"PkiCipher",             store_cipher_type, ITEM(res_client.pki_cipher), 0, 0, 0},
102    {"PkiDigest",             store_digest_type, ITEM(res_client.pki_digest), 0, 0, 0},
103 #endif
104    {"TlsAuthenticate",       store_bool,    ITEM(res_client.tls_authenticate),  0, 0, 0},
105    {"TlsEnable",             store_bool,    ITEM(res_client.tls_enable),  0, 0, 0},
106    {"TlsRequire",            store_bool,    ITEM(res_client.tls_require), 0, 0, 0},
107    {"TlsCaCertificateFile",  store_dir,     ITEM(res_client.tls_ca_certfile), 0, 0, 0},
108    {"TlsCaCertificateDir",   store_dir,     ITEM(res_client.tls_ca_certdir), 0, 0, 0},
109    {"TlsCertificate",        store_dir,     ITEM(res_client.tls_certfile), 0, 0, 0},
110    {"TlsKey",                store_dir,     ITEM(res_client.tls_keyfile), 0, 0, 0},
111    {"VerId",                 store_str,     ITEM(res_client.verid), 0, 0, 0},
112    {"MaximumBandwidthPerJob",store_speed,   ITEM(res_client.max_bandwidth_per_job), 0, 0, 0},
113    {"CommCompression",       store_bool,    ITEM(res_client.comm_compression), 0, ITEM_DEFAULT, true},
114    {"DisableCommand",        store_alist_str, ITEM(res_client.disable_cmds), 0, 0, 0},
115    {NULL, NULL, {0}, 0, 0, 0}
116 };
117 
118 /* Directors that can use our services */
119 static RES_ITEM dir_items[] = {
120    {"Name",        store_name,     ITEM(res_dir.hdr.name),  0, ITEM_REQUIRED, 0},
121    {"Description", store_str,      ITEM(res_dir.hdr.desc),  0, 0, 0},
122    {"Password",    store_password, ITEM(res_dir.password),  0, ITEM_REQUIRED, 0},
123    {"Address",     store_str,      ITEM(res_dir.address),   0, 0, 0},
124    {"Monitor",     store_bool,   ITEM(res_dir.monitor),   0, ITEM_DEFAULT, 0},
125    {"Remote",      store_bool,   ITEM(res_dir.remote),   0, ITEM_DEFAULT, 0},
126    {"TlsAuthenticate",      store_bool,    ITEM(res_dir.tls_authenticate), 0, 0, 0},
127    {"TlsEnable",            store_bool,    ITEM(res_dir.tls_enable), 0, 0, 0},
128    {"TlsRequire",           store_bool,    ITEM(res_dir.tls_require), 0, 0, 0},
129    {"TlsVerifyPeer",        store_bool,    ITEM(res_dir.tls_verify_peer), 0, ITEM_DEFAULT, 1},
130    {"TlsCaCertificateFile", store_dir,       ITEM(res_dir.tls_ca_certfile), 0, 0, 0},
131    {"TlsCaCertificateDir",  store_dir,       ITEM(res_dir.tls_ca_certdir), 0, 0, 0},
132    {"TlsCertificate",       store_dir,       ITEM(res_dir.tls_certfile), 0, 0, 0},
133    {"TlsKey",               store_dir,       ITEM(res_dir.tls_keyfile), 0, 0, 0},
134    {"TlsDhFile",            store_dir,       ITEM(res_dir.tls_dhfile), 0, 0, 0},
135    {"TlsAllowedCn",         store_alist_str, ITEM(res_dir.tls_allowed_cns), 0, 0, 0},
136    {"MaximumBandwidthPerJob", store_speed,     ITEM(res_dir.max_bandwidth_per_job), 0, 0, 0},
137    {"DisableCommand",        store_alist_str, ITEM(res_dir.disable_cmds), 0, 0, 0},
138    {"Console",              store_res, ITEM(res_dir.console),  R_CONSOLE, 0, 0},
139    {NULL, NULL, {0}, 0, 0, 0}
140 };
141 
142 /* Consoles that we can use to connect a Director */
143 static RES_ITEM cons_items[] = {
144    {"Name",        store_name,     ITEM(res_cons.hdr.name),  0, ITEM_REQUIRED, 0},
145    {"Description", store_str,      ITEM(res_cons.hdr.desc),  0, 0, 0},
146    {"Password",    store_password, ITEM(res_cons.password),  0, ITEM_REQUIRED, 0},
147    {"Address",     store_str,      ITEM(res_cons.address),   0, 0, 0},
148    {"DirPort",        store_pint32,    ITEM(res_cons.DIRport),  0, ITEM_DEFAULT, 9101},
149    {"TlsAuthenticate",      store_bool,    ITEM(res_cons.tls_authenticate), 0, 0, 0},
150    {"TlsEnable",            store_bool,    ITEM(res_cons.tls_enable), 0, 0, 0},
151    {"TlsRequire",           store_bool,    ITEM(res_cons.tls_require), 0, 0, 0},
152    {"TlsVerifyPeer",        store_bool,    ITEM(res_cons.tls_verify_peer), 0, ITEM_DEFAULT, 1},
153    {"TlsCaCertificateFile", store_dir,       ITEM(res_cons.tls_ca_certfile), 0, 0, 0},
154    {"TlsCaCertificateDir",  store_dir,       ITEM(res_cons.tls_ca_certdir), 0, 0, 0},
155    {"TlsCertificate",       store_dir,       ITEM(res_cons.tls_certfile), 0, 0, 0},
156    {"TlsKey",               store_dir,       ITEM(res_cons.tls_keyfile), 0, 0, 0},
157    {"TlsDhFile",            store_dir,       ITEM(res_cons.tls_dhfile), 0, 0, 0},
158    {"TlsAllowedCn",         store_alist_str, ITEM(res_cons.tls_allowed_cns), 0, 0, 0},
159    {NULL, NULL, {0}, 0, 0, 0}
160 };
161 
162 /* Message resource */
163 extern RES_ITEM msgs_items[];
164 
165 /* Statistics resource */
166 extern RES_ITEM collector_items[];
167 
168 
169 /*
170  * This is the master resource definition.
171  * It must have one item for each of the resources.
172  */
173 RES_TABLE resources[] = {
174    {"Director",      dir_items,        R_DIRECTOR},
175    {"FileDaemon",    cli_items,        R_CLIENT},
176    {"Messages",      msgs_items,       R_MSGS},
177    {"Console",       cons_items,       R_CONSOLE},
178    {"Statistics",    collector_items,  R_COLLECTOR},
179    {"Client",        cli_items,        R_CLIENT},     /* alias for filedaemon */
180    {NULL,            NULL,             0}
181 };
182 
183 struct s_ct ciphertypes[] = {
184    {"aes128",        CRYPTO_CIPHER_AES_128_CBC},
185    {"aes192",        CRYPTO_CIPHER_AES_192_CBC},
186    {"aes256",        CRYPTO_CIPHER_AES_256_CBC},
187    {"blowfish",      CRYPTO_CIPHER_BLOWFISH_CBC},
188    {NULL,            0}
189 };
190 
191 struct s_ct digesttypes[] = {
192    {"md5",         CRYPTO_DIGEST_MD5},
193    {"sha1",        CRYPTO_DIGEST_SHA1},
194    {"sha256",      CRYPTO_DIGEST_SHA256},
195 //   {"sha512",      CRYPTO_DIGEST_SHA512}, /* Not working yet */
196    {NULL,                             0}
197 };
198 
199 /*
200  * Store cipher type
201  *
202  */
store_cipher_type(LEX * lc,RES_ITEM * item,int index,int pass)203 void store_cipher_type(LEX *lc, RES_ITEM *item, int index, int pass)
204 {
205    int i;
206 
207    lex_get_token(lc, T_NAME);
208    /* Store the type both pass 1 and pass 2 */
209    for (i=0; ciphertypes[i].type_name; i++) {
210       if (strcasecmp(lc->str, ciphertypes[i].type_name) == 0) {
211          *(uint32_t *)(item->value) = ciphertypes[i].type_value;
212          i = 0;
213          break;
214       }
215    }
216    if (i != 0) {
217       scan_err1(lc, _("Expected a Cipher Type keyword, got: %s"), lc->str);
218    }
219    scan_to_eol(lc);
220    set_bit(index, res_all.hdr.item_present);
221 }
222 
223 /*
224  * Store digest type
225  *
226  */
store_digest_type(LEX * lc,RES_ITEM * item,int index,int pass)227 void store_digest_type(LEX *lc, RES_ITEM *item, int index, int pass)
228 {
229    int i;
230 
231    lex_get_token(lc, T_NAME);
232    /* Store the type both pass 1 and pass 2 */
233    for (i=0; digesttypes[i].type_name; i++) {
234       if (strcasecmp(lc->str, digesttypes[i].type_name) == 0) {
235          *(uint32_t *)(item->value) = digesttypes[i].type_value;
236          i = 0;
237          break;
238       }
239    }
240    if (i != 0) {
241       scan_err1(lc, _("Expected a Cipher Type keyword, got: %s"), lc->str);
242    }
243    scan_to_eol(lc);
244    set_bit(index, res_all.hdr.item_present);
245 }
246 
247 /* Dump contents of resource */
dump_resource(int type,RES * ares,void sendit (void * sock,const char * fmt,...),void * sock)248 void dump_resource(int type, RES *ares, void sendit(void *sock, const char *fmt, ...), void *sock)
249 {
250    URES *res = (URES *)ares;
251    int recurse = 1;
252 
253    if (res == NULL) {
254       sendit(sock, "No record for %d %s\n", type, res_to_str(type));
255       return;
256    }
257    if (type < 0) {                    /* no recursion */
258       type = - type;
259       recurse = 0;
260    }
261    switch (type) {
262    case R_CONSOLE:
263       sendit(sock, "Console: name=%s password=%s\n", ares->name,
264              res->res_cons.password);
265       break;
266    case R_DIRECTOR:
267       sendit(sock, "Director: name=%s password=%s\n", ares->name,
268               res->res_dir.password);
269       break;
270    case R_CLIENT:
271       sendit(sock, "Client: name=%s FDport=%d\n", ares->name,
272               get_first_port_host_order(res->res_client.FDaddrs));
273       break;
274    case R_MSGS:
275       sendit(sock, "Messages: name=%s\n", res->res_msgs.hdr.name);
276       if (res->res_msgs.mail_cmd)
277          sendit(sock, "      mailcmd=%s\n", res->res_msgs.mail_cmd);
278       if (res->res_msgs.operator_cmd)
279          sendit(sock, "      opcmd=%s\n", res->res_msgs.operator_cmd);
280       break;
281    case R_COLLECTOR:
282       dump_collector_resource(res->res_collector, sendit, sock);
283       break;
284    default:
285       sendit(sock, "Unknown resource type %d\n", type);
286    }
287    ares = GetNextRes(type, ares);
288    if (recurse && ares) {
289       dump_resource(type, ares, sendit, sock);
290    }
291 }
292 
293 
294 /*
295  * Free memory of resource.
296  * NB, we don't need to worry about freeing any references
297  * to other resources as they will be freed when that
298  * resource chain is traversed.  Mainly we worry about freeing
299  * allocated strings (names).
300  */
free_resource(RES * sres,int type)301 void free_resource(RES *sres, int type)
302 {
303    URES *res = (URES *)sres;
304 
305    if (res == NULL) {
306       return;
307    }
308 
309    /* common stuff -- free the resource name */
310    if (res->res_dir.hdr.name) {
311       free(res->res_dir.hdr.name);
312    }
313    if (res->res_dir.hdr.desc) {
314       free(res->res_dir.hdr.desc);
315    }
316    switch (type) {
317    case R_DIRECTOR:
318       if (res->res_dir.password) {
319          free(res->res_dir.password);
320       }
321       if (res->res_dir.address) {
322          free(res->res_dir.address);
323       }
324       if (res->res_dir.tls_ctx) {
325          free_tls_context(res->res_dir.tls_ctx);
326       }
327       if (res->res_dir.tls_ca_certfile) {
328          free(res->res_dir.tls_ca_certfile);
329       }
330       if (res->res_dir.tls_ca_certdir) {
331          free(res->res_dir.tls_ca_certdir);
332       }
333       if (res->res_dir.tls_certfile) {
334          free(res->res_dir.tls_certfile);
335       }
336       if (res->res_dir.tls_keyfile) {
337          free(res->res_dir.tls_keyfile);
338       }
339       if (res->res_dir.tls_dhfile) {
340          free(res->res_dir.tls_dhfile);
341       }
342       if (res->res_dir.tls_allowed_cns) {
343          delete res->res_dir.tls_allowed_cns;
344       }
345       if (res->res_dir.disable_cmds) {
346          delete res->res_dir.disable_cmds;
347       }
348       if (res->res_dir.disabled_cmds_array) {
349          free(res->res_dir.disabled_cmds_array);
350       }
351       break;
352    case R_CONSOLE:
353       if (res->res_cons.password) {
354          free(res->res_cons.password);
355       }
356       if (res->res_cons.address) {
357          free(res->res_cons.address);
358       }
359       if (res->res_cons.tls_ctx) {
360          free_tls_context(res->res_cons.tls_ctx);
361       }
362       if (res->res_cons.tls_ca_certfile) {
363          free(res->res_cons.tls_ca_certfile);
364       }
365       if (res->res_cons.tls_ca_certdir) {
366          free(res->res_cons.tls_ca_certdir);
367       }
368       if (res->res_cons.tls_certfile) {
369          free(res->res_cons.tls_certfile);
370       }
371       if (res->res_cons.tls_keyfile) {
372          free(res->res_cons.tls_keyfile);
373       }
374       if (res->res_cons.tls_dhfile) {
375          free(res->res_cons.tls_dhfile);
376       }
377       if (res->res_cons.tls_allowed_cns) {
378          delete res->res_cons.tls_allowed_cns;
379       }
380       break;
381     case R_CLIENT:
382       if (res->res_client.working_directory) {
383          free(res->res_client.working_directory);
384       }
385       if (res->res_client.pid_directory) {
386          free(res->res_client.pid_directory);
387       }
388       if (res->res_client.subsys_directory) {
389          free(res->res_client.subsys_directory);
390       }
391       if (res->res_client.scripts_directory) {
392          free(res->res_client.scripts_directory);
393       }
394       if (res->res_client.plugin_directory) {
395          free(res->res_client.plugin_directory);
396       }
397       if (res->res_client.FDaddrs) {
398          free_addresses(res->res_client.FDaddrs);
399       }
400       if (res->res_client.FDsrc_addr) {
401          free_addresses(res->res_client.FDsrc_addr);
402       }
403       if (res->res_client.snapshot_command) {
404          free(res->res_client.snapshot_command);
405       }
406       if (res->res_client.pki_keypair_file) {
407          free(res->res_client.pki_keypair_file);
408       }
409       if (res->res_client.pki_keypair) {
410          crypto_keypair_free(res->res_client.pki_keypair);
411       }
412 
413       if (res->res_client.pki_signing_key_files) {
414          delete res->res_client.pki_signing_key_files;
415       }
416       if (res->res_client.pki_signers) {
417          X509_KEYPAIR *keypair;
418          foreach_alist(keypair, res->res_client.pki_signers) {
419             crypto_keypair_free(keypair);
420          }
421          delete res->res_client.pki_signers;
422       }
423 
424       if (res->res_client.pki_master_key_files) {
425          delete res->res_client.pki_master_key_files;
426       }
427 
428       if (res->res_client.pki_recipients) {
429          X509_KEYPAIR *keypair;
430          foreach_alist(keypair, res->res_client.pki_recipients) {
431             crypto_keypair_free(keypair);
432          }
433          delete res->res_client.pki_recipients;
434       }
435 
436       if (res->res_client.tls_ctx) {
437          free_tls_context(res->res_client.tls_ctx);
438       }
439       if (res->res_client.tls_ca_certfile) {
440          free(res->res_client.tls_ca_certfile);
441       }
442       if (res->res_client.tls_ca_certdir) {
443          free(res->res_client.tls_ca_certdir);
444       }
445       if (res->res_client.tls_certfile) {
446          free(res->res_client.tls_certfile);
447       }
448       if (res->res_client.tls_keyfile) {
449          free(res->res_client.tls_keyfile);
450       }
451       if (res->res_client.disable_cmds) {
452          delete res->res_client.disable_cmds;
453       }
454       if (res->res_client.disabled_cmds_array) {
455          free(res->res_client.disabled_cmds_array);
456       }
457       if (res->res_client.verid) {
458          free(res->res_client.verid);
459       }
460       break;
461    case R_MSGS:
462       if (res->res_msgs.mail_cmd) {
463          free(res->res_msgs.mail_cmd);
464       }
465       if (res->res_msgs.operator_cmd) {
466          free(res->res_msgs.operator_cmd);
467       }
468       free_msgs_res((MSGS *)res);  /* free message resource */
469       res = NULL;
470       break;
471    case R_COLLECTOR:
472       free_collector_resource(res->res_collector);
473       break;
474    default:
475       printf(_("Unknown resource type %d\n"), type);
476    }
477    /* Common stuff again -- free the resource, recurse to next one */
478    if (res) {
479       free(res);
480    }
481 }
482 
483 /* Save the new resource by chaining it into the head list for
484  * the resource. If this is pass 2, we update any resource
485  * pointers (currently only in the Job resource).
486  */
save_resource(CONFIG * config,int type,RES_ITEM * items,int pass)487 bool save_resource(CONFIG *config, int type, RES_ITEM *items, int pass)
488 {
489    URES *res;
490    CONSRES *cons;
491    int rindex = type - r_first;
492    int i, size;
493    int error = 0;
494 
495    /*
496     * Ensure that all required items are present
497     */
498    for (i=0; items[i].name; i++) {
499       if (items[i].flags & ITEM_REQUIRED) {
500          if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
501             Mmsg(config->m_errmsg, _("\"%s\" directive is required in \"%s\" resource, but not found.\n"),
502                  items[i].name, resources[rindex].name);
503             return false;
504          }
505       }
506    }
507 
508    /* During pass 2, we looked up pointers to all the resources
509     * referrenced in the current resource, , now we
510     * must copy their address from the static record to the allocated
511     * record.
512     */
513    if (pass == 2) {
514       switch (type) {
515          /* Resources not containing a resource */
516          case R_MSGS:
517             break;
518 
519          /* Resources containing another resource */
520          case R_DIRECTOR:
521             if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
522                Mmsg(config->m_errmsg, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
523                return false;
524             }
525             res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
526             res->res_dir.disable_cmds = res_all.res_dir.disable_cmds;
527             res->res_dir.console = res_all.res_dir.console;
528             if (res_all.res_dir.remote && !res_all.res_dir.console) {
529                if ((cons = (CONSRES *)GetNextRes(R_CONSOLE, NULL)) == NULL) {
530                   Mmsg(config->m_errmsg, _("Cannot find any Console resource for remote access\n"));
531                   return false;
532                }
533                res->res_dir.console = cons;
534             }
535             break;
536          /* Resources containing another resource */
537          case R_CONSOLE:
538             break;
539          case R_CLIENT:
540             if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_dir.hdr.name)) == NULL) {
541                Mmsg(config->m_errmsg, _("Cannot find Client resource %s\n"), res_all.res_dir.hdr.name);
542                return false;
543             }
544             res->res_client.pki_signing_key_files = res_all.res_client.pki_signing_key_files;
545             res->res_client.pki_master_key_files = res_all.res_client.pki_master_key_files;
546 
547             res->res_client.pki_signers = res_all.res_client.pki_signers;
548             res->res_client.pki_recipients = res_all.res_client.pki_recipients;
549 
550             res->res_client.messages = res_all.res_client.messages;
551             res->res_client.disable_cmds = res_all.res_client.disable_cmds;
552             break;
553          case R_COLLECTOR:
554             if ((res = (URES *)GetResWithName(R_COLLECTOR, res_all.res_collector.hdr.name)) == NULL) {
555                Mmsg(config->m_errmsg, _("Cannot find Statistics resource %s\n"), res_all.res_collector.hdr.name);
556                return false;
557             }
558             res->res_collector.metrics = res_all.res_collector.metrics;
559             // Dmsg2(100, "metrics = 0x%p 0x%p\n", res->res_collector.metrics, res_all.res_collector.metrics);
560             break;
561          default:
562             Emsg1(M_ERROR, 0, _("Unknown resource type %d\n"), type);
563             error = 1;
564             break;
565       }
566       /* Note, the resource name was already saved during pass 1,
567        * so here, we can just release it.
568        */
569       if (res_all.res_dir.hdr.name) {
570          free(res_all.res_dir.hdr.name);
571          res_all.res_dir.hdr.name = NULL;
572       }
573       if (res_all.res_dir.hdr.desc) {
574          free(res_all.res_dir.hdr.desc);
575          res_all.res_dir.hdr.desc = NULL;
576       }
577       return true;
578    }
579 
580    /* The following code is only executed on pass 1 */
581    switch (type) {
582       case R_DIRECTOR:
583          size = sizeof(DIRRES);
584          break;
585       case R_CONSOLE:
586          size = sizeof(CONSRES);
587          break;
588       case R_CLIENT:
589          size = sizeof(CLIENT);
590          break;
591       case R_MSGS:
592          size = sizeof(MSGS);
593          break;
594       case R_COLLECTOR:
595          size = sizeof(COLLECTOR);
596          break;
597       default:
598          printf(_("Unknown resource type %d\n"), type);
599          error = 1;
600          size = 1;
601          break;
602    }
603    /* Common */
604    if (!error) {
605       if (!config->insert_res(rindex, size)) {
606          return false;
607       }
608    }
609    return true;
610 }
611 
parse_fd_config(CONFIG * config,const char * configfile,int exit_code)612 bool parse_fd_config(CONFIG *config, const char *configfile, int exit_code)
613 {
614    config->init(configfile, NULL, exit_code, (void *)&res_all, res_all_size,
615       r_first, r_last, resources, &res_head);
616    return config->parse_config();
617 }
618