2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2008 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version three of the GNU Affero General Public
10 License as published by the Free Software Foundation and included
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU Affero General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 Bacula® is a registered trademark of Kern Sibbald.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
29 * Main configuration file parser for Bacula File Daemon (Client)
30 * some parts may be split into separate files such as
31 * the schedule configuration (sch_config.c).
33 * Note, the configuration file parser consists of three parts
35 * 1. The generic lexical scanner in lib/lex.c and lib/lex.h
37 * 2. The generic config scanner in lib/parse_config.c and
39 * These files contain the parser code, some utility
40 * routines, and the common store routines (name, int,
43 * 3. The daemon specific file, which contains the Resource
44 * definitions as well as any specific store routines
45 * for the resource records.
47 * Kern Sibbald, September MM
55 /* Define the first and last resource ID record
56 * types. Note, these should be unique for each
57 * daemon though not a requirement.
59 int32_t r_first = R_FIRST;
60 int32_t r_last = R_LAST;
61 static RES *sres_head[R_LAST - R_FIRST + 1];
62 RES **res_head = sres_head;
65 /* Forward referenced subroutines */
68 /* We build the current resource here as we are
69 * scanning the resource configuration definition,
70 * then move it to allocated memory when the resource
74 extern "C" { // work around visual compiler mangling variables
80 int32_t res_all_size = sizeof(res_all);
82 /* Definition of records permitted within each
83 * resource with the routine to process the record
87 /* Client or File daemon "Global" resources */
88 static RES_ITEM cli_items[] = {
89 {"name", store_name, ITEM(res_client.hdr.name), 0, ITEM_REQUIRED, 0},
90 {"description", store_str, ITEM(res_client.hdr.desc), 0, 0, 0},
91 {"fdport", store_addresses_port, ITEM(res_client.FDaddrs), 0, ITEM_DEFAULT, 9102},
92 {"fdaddress", store_addresses_address, ITEM(res_client.FDaddrs), 0, ITEM_DEFAULT, 9102},
93 {"fdaddresses", store_addresses, ITEM(res_client.FDaddrs), 0, ITEM_DEFAULT, 9102},
94 {"fdsourceaddress", store_addresses_address, ITEM(res_client.FDsrc_addr), 0, ITEM_DEFAULT, 0},
96 {"workingdirectory", store_dir, ITEM(res_client.working_directory), 0, ITEM_REQUIRED, 0},
97 {"piddirectory", store_dir, ITEM(res_client.pid_directory), 0, ITEM_REQUIRED, 0},
98 {"subsysdirectory", store_dir, ITEM(res_client.subsys_directory), 0, 0, 0},
99 {"plugindirectory", store_dir, ITEM(res_client.plugin_directory), 0, 0, 0},
100 {"scriptsdirectory", store_dir, ITEM(res_client.scripts_directory), 0, 0, 0},
101 {"maximumconcurrentjobs", store_pint32, ITEM(res_client.MaxConcurrentJobs), 0, ITEM_DEFAULT, 20},
102 {"messages", store_res, ITEM(res_client.messages), R_MSGS, 0, 0},
103 {"sdconnecttimeout", store_time,ITEM(res_client.SDConnectTimeout), 0, ITEM_DEFAULT, 60 * 30},
104 {"heartbeatinterval", store_time, ITEM(res_client.heartbeat_interval), 0, ITEM_DEFAULT, 0},
105 {"maximumnetworkbuffersize", store_pint32, ITEM(res_client.max_network_buffer_size), 0, 0, 0},
106 #ifdef DATA_ENCRYPTION
107 {"pkisignatures", store_bool, ITEM(res_client.pki_sign), 0, ITEM_DEFAULT, 0},
108 {"pkiencryption", store_bool, ITEM(res_client.pki_encrypt), 0, ITEM_DEFAULT, 0},
109 {"pkikeypair", store_dir, ITEM(res_client.pki_keypair_file), 0, 0, 0},
110 {"pkisigner", store_alist_str, ITEM(res_client.pki_signing_key_files), 0, 0, 0},
111 {"pkimasterkey", store_alist_str, ITEM(res_client.pki_master_key_files), 0, 0, 0},
113 {"tlsauthenticate", store_bool, ITEM(res_client.tls_authenticate), 0, 0, 0},
114 {"tlsenable", store_bool, ITEM(res_client.tls_enable), 0, 0, 0},
115 {"tlsrequire", store_bool, ITEM(res_client.tls_require), 0, 0, 0},
116 {"tlscacertificatefile", store_dir, ITEM(res_client.tls_ca_certfile), 0, 0, 0},
117 {"tlscacertificatedir", store_dir, ITEM(res_client.tls_ca_certdir), 0, 0, 0},
118 {"tlscertificate", store_dir, ITEM(res_client.tls_certfile), 0, 0, 0},
119 {"tlskey", store_dir, ITEM(res_client.tls_keyfile), 0, 0, 0},
120 {"verid", store_str, ITEM(res_client.verid), 0, 0, 0},
121 {"maximumbandwidth", store_speed, ITEM(res_client.max_bandwidth), 0, 0, 0},
122 {NULL, NULL, {0}, 0, 0, 0}
125 /* Directors that can use our services */
126 static RES_ITEM dir_items[] = {
127 {"name", store_name, ITEM(res_dir.hdr.name), 0, ITEM_REQUIRED, 0},
128 {"description", store_str, ITEM(res_dir.hdr.desc), 0, 0, 0},
129 {"password", store_password, ITEM(res_dir.password), 0, ITEM_REQUIRED, 0},
130 {"address", store_str, ITEM(res_dir.address), 0, 0, 0},
131 {"monitor", store_bool, ITEM(res_dir.monitor), 0, ITEM_DEFAULT, 0},
132 {"tlsauthenticate", store_bool, ITEM(res_dir.tls_authenticate), 0, 0, 0},
133 {"tlsenable", store_bool, ITEM(res_dir.tls_enable), 0, 0, 0},
134 {"tlsrequire", store_bool, ITEM(res_dir.tls_require), 0, 0, 0},
135 {"tlsverifypeer", store_bool, ITEM(res_dir.tls_verify_peer), 0, ITEM_DEFAULT, 1},
136 {"tlscacertificatefile", store_dir, ITEM(res_dir.tls_ca_certfile), 0, 0, 0},
137 {"tlscacertificatedir", store_dir, ITEM(res_dir.tls_ca_certdir), 0, 0, 0},
138 {"tlscertificate", store_dir, ITEM(res_dir.tls_certfile), 0, 0, 0},
139 {"tlskey", store_dir, ITEM(res_dir.tls_keyfile), 0, 0, 0},
140 {"tlsdhfile", store_dir, ITEM(res_dir.tls_dhfile), 0, 0, 0},
141 {"tlsallowedcn", store_alist_str, ITEM(res_dir.tls_allowed_cns), 0, 0, 0},
142 {"maximumbandwidth", store_speed, ITEM(res_dir.max_bandwidth), 0, 0, 0},
143 {NULL, NULL, {0}, 0, 0, 0}
146 /* Message resource */
147 extern RES_ITEM msgs_items[];
150 * This is the master resource definition.
151 * It must have one item for each of the resources.
153 RES_TABLE resources[] = {
154 {"director", dir_items, R_DIRECTOR},
155 {"filedaemon", cli_items, R_CLIENT},
156 {"client", cli_items, R_CLIENT}, /* alias for filedaemon */
157 {"messages", msgs_items, R_MSGS},
162 /* Dump contents of resource */
163 void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fmt, ...), void *sock)
165 URES *res = (URES *)reshdr;
169 sendit(sock, "No record for %d %s\n", type, res_to_str(type));
172 if (type < 0) { /* no recursion */
178 sendit(sock, "Director: name=%s password=%s\n", reshdr->name,
179 res->res_dir.password);
182 sendit(sock, "Client: name=%s FDport=%d\n", reshdr->name,
183 get_first_port_host_order(res->res_client.FDaddrs));
186 sendit(sock, "Messages: name=%s\n", res->res_msgs.hdr.name);
187 if (res->res_msgs.mail_cmd)
188 sendit(sock, " mailcmd=%s\n", res->res_msgs.mail_cmd);
189 if (res->res_msgs.operator_cmd)
190 sendit(sock, " opcmd=%s\n", res->res_msgs.operator_cmd);
193 sendit(sock, "Unknown resource type %d\n", type);
195 if (recurse && res->res_dir.hdr.next) {
196 dump_resource(type, res->res_dir.hdr.next, sendit, sock);
201 * Free memory of resource.
202 * NB, we don't need to worry about freeing any references
203 * to other resources as they will be freed when that
204 * resource chain is traversed. Mainly we worry about freeing
205 * allocated strings (names).
207 void free_resource(RES *sres, int type)
210 URES *res = (URES *)sres;
216 /* common stuff -- free the resource name */
217 nres = (RES *)res->res_dir.hdr.next;
218 if (res->res_dir.hdr.name) {
219 free(res->res_dir.hdr.name);
221 if (res->res_dir.hdr.desc) {
222 free(res->res_dir.hdr.desc);
226 if (res->res_dir.password) {
227 free(res->res_dir.password);
229 if (res->res_dir.address) {
230 free(res->res_dir.address);
232 if (res->res_dir.tls_ctx) {
233 free_tls_context(res->res_dir.tls_ctx);
235 if (res->res_dir.tls_ca_certfile) {
236 free(res->res_dir.tls_ca_certfile);
238 if (res->res_dir.tls_ca_certdir) {
239 free(res->res_dir.tls_ca_certdir);
241 if (res->res_dir.tls_certfile) {
242 free(res->res_dir.tls_certfile);
244 if (res->res_dir.tls_keyfile) {
245 free(res->res_dir.tls_keyfile);
247 if (res->res_dir.tls_dhfile) {
248 free(res->res_dir.tls_dhfile);
250 if (res->res_dir.tls_allowed_cns) {
251 delete res->res_dir.tls_allowed_cns;
255 if (res->res_client.working_directory) {
256 free(res->res_client.working_directory);
258 if (res->res_client.pid_directory) {
259 free(res->res_client.pid_directory);
261 if (res->res_client.subsys_directory) {
262 free(res->res_client.subsys_directory);
264 if (res->res_client.scripts_directory) {
265 free(res->res_client.scripts_directory);
267 if (res->res_client.plugin_directory) {
268 free(res->res_client.plugin_directory);
270 if (res->res_client.FDaddrs) {
271 free_addresses(res->res_client.FDaddrs);
273 if (res->res_client.FDsrc_addr) {
274 free_addresses(res->res_client.FDsrc_addr);
277 if (res->res_client.pki_keypair_file) {
278 free(res->res_client.pki_keypair_file);
280 if (res->res_client.pki_keypair) {
281 crypto_keypair_free(res->res_client.pki_keypair);
284 if (res->res_client.pki_signing_key_files) {
285 delete res->res_client.pki_signing_key_files;
287 if (res->res_client.pki_signers) {
288 X509_KEYPAIR *keypair;
289 foreach_alist(keypair, res->res_client.pki_signers) {
290 crypto_keypair_free(keypair);
292 delete res->res_client.pki_signers;
295 if (res->res_client.pki_master_key_files) {
296 delete res->res_client.pki_master_key_files;
299 if (res->res_client.pki_recipients) {
300 X509_KEYPAIR *keypair;
301 foreach_alist(keypair, res->res_client.pki_recipients) {
302 crypto_keypair_free(keypair);
304 delete res->res_client.pki_recipients;
307 if (res->res_client.tls_ctx) {
308 free_tls_context(res->res_client.tls_ctx);
310 if (res->res_client.tls_ca_certfile) {
311 free(res->res_client.tls_ca_certfile);
313 if (res->res_client.tls_ca_certdir) {
314 free(res->res_client.tls_ca_certdir);
316 if (res->res_client.tls_certfile) {
317 free(res->res_client.tls_certfile);
319 if (res->res_client.tls_keyfile) {
320 free(res->res_client.tls_keyfile);
322 if (res->res_client.verid) {
323 free(res->res_client.verid);
327 if (res->res_msgs.mail_cmd)
328 free(res->res_msgs.mail_cmd);
329 if (res->res_msgs.operator_cmd)
330 free(res->res_msgs.operator_cmd);
331 free_msgs_res((MSGS *)res); /* free message resource */
335 printf(_("Unknown resource type %d\n"), type);
337 /* Common stuff again -- free the resource, recurse to next one */
342 free_resource(nres, type);
346 /* Save the new resource by chaining it into the head list for
347 * the resource. If this is pass 2, we update any resource
348 * pointers (currently only in the Job resource).
350 void save_resource(int type, RES_ITEM *items, int pass)
353 int rindex = type - r_first;
358 * Ensure that all required items are present
360 for (i=0; items[i].name; i++) {
361 if (items[i].flags & ITEM_REQUIRED) {
362 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
363 Emsg2(M_ABORT, 0, _("%s item is required in %s resource, but not found.\n"),
364 items[i].name, resources[rindex]);
369 /* During pass 2, we looked up pointers to all the resources
370 * referrenced in the current resource, , now we
371 * must copy their address from the static record to the allocated
376 /* Resources not containing a resource */
380 /* Resources containing another resource */
382 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
383 Emsg1(M_ABORT, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
385 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
388 if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_dir.hdr.name)) == NULL) {
389 Emsg1(M_ABORT, 0, _("Cannot find Client resource %s\n"), res_all.res_dir.hdr.name);
391 res->res_client.pki_signing_key_files = res_all.res_client.pki_signing_key_files;
392 res->res_client.pki_master_key_files = res_all.res_client.pki_master_key_files;
394 res->res_client.pki_signers = res_all.res_client.pki_signers;
395 res->res_client.pki_recipients = res_all.res_client.pki_recipients;
397 res->res_client.messages = res_all.res_client.messages;
400 Emsg1(M_ERROR, 0, _("Unknown resource type %d\n"), type);
404 /* Note, the resoure name was already saved during pass 1,
405 * so here, we can just release it.
407 if (res_all.res_dir.hdr.name) {
408 free(res_all.res_dir.hdr.name);
409 res_all.res_dir.hdr.name = NULL;
411 if (res_all.res_dir.hdr.desc) {
412 free(res_all.res_dir.hdr.desc);
413 res_all.res_dir.hdr.desc = NULL;
418 /* The following code is only executed on pass 1 */
421 size = sizeof(DIRRES);
424 size = sizeof(CLIENT);
430 printf(_("Unknown resource type %d\n"), type);
437 res = (URES *)malloc(size);
438 memcpy(res, &res_all, size);
439 if (!res_head[rindex]) {
440 res_head[rindex] = (RES *)res; /* store first entry */
443 /* Add new res to end of chain */
444 for (last=next=res_head[rindex]; next; next=next->next) {
446 if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
447 Emsg2(M_ERROR_TERM, 0,
448 _("Attempt to define second %s resource named \"%s\" is not permitted.\n"),
449 resources[rindex].name, res->res_dir.hdr.name);
452 last->next = (RES *)res;
453 Dmsg2(90, "Inserting %s res: %s\n", res_to_str(type),
454 res->res_dir.hdr.name);
459 bool parse_fd_config(CONFIG *config, const char *configfile, int exit_code)
461 config->init(configfile, NULL, exit_code, (void *)&res_all, res_all_size,
462 r_first, r_last, resources, res_head);
463 return config->parse_config();