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 Tray Monitor.
21 *
22 * Adapted from dird_conf.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 * Nicolas Boichat, August MMIV
39 *
40 */
41
42 #include "common.h"
43 #include "tray_conf.h"
44
45 worker *worker_start();
46 void worker_stop(worker *);
47
48 /* Define the first and last resource ID record
49 * types. Note, these should be unique for each
50 * daemon though not a requirement.
51 */
52 int32_t r_first = R_FIRST;
53 int32_t r_last = R_LAST;
54 RES_HEAD **res_head;
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 URES res_all;
62 int32_t res_all_size = sizeof(res_all);
63
64
65 /* Definition of records permitted within each
66 * resource with the routine to process the record
67 * information. NOTE! quoted names must be in lower case.
68 */
69 /*
70 * Monitor Resource
71 *
72 * name handler value code flags default_value
73 */
74 static RES_ITEM mon_items[] = {
75 {"Name", store_name, ITEM(res_monitor.hdr.name), 0, ITEM_REQUIRED, 0},
76 {"Description", store_str, ITEM(res_monitor.hdr.desc), 0, 0, 0},
77 {"requiressl", store_bool, ITEM(res_monitor.require_ssl), 1, ITEM_DEFAULT, 0},
78 {"RefreshInterval", store_time,ITEM(res_monitor.RefreshInterval), 0, ITEM_DEFAULT, 60},
79 {"CommCompression", store_bool, ITEM(res_monitor.comm_compression), 0, ITEM_DEFAULT, true},
80 {"CommandDirectory", store_dir, ITEM(res_monitor.command_dir), 0, 0, 0},
81 {"DisplayAdvancedOptions", store_bool, ITEM(res_monitor.display_advanced_options), 0, 0, 0},
82 {NULL, NULL, {0}, 0, 0, 0}
83 };
84
85 /* Director's that we can contact */
86 static RES_ITEM dir_items[] = {
87 {"Name", store_name, ITEM(res_main.hdr.name), 0, ITEM_REQUIRED, 0},
88 {"Description", store_str, ITEM(res_main.hdr.desc), 0, 0, 0},
89 {"Port", store_pint32, ITEM(res_main.port), 0, ITEM_DEFAULT, 9101},
90 {"Address", store_str, ITEM(res_main.address), 0, ITEM_REQUIRED, 0},
91 {"Password", store_password, ITEM(res_main.password), 0, ITEM_REQUIRED, 0},
92 {"Monitor", store_bool, ITEM(res_main.use_monitor), 0, ITEM_DEFAULT, 0},
93 {"ConnectTimeout", store_time,ITEM(res_main.connect_timeout), 0, ITEM_DEFAULT, 10},
94 {"UseSetIp", store_bool, ITEM(res_main.use_setip), 0, 0, 0},
95 {"TlsEnable", store_bool, ITEM(res_main.tls_enable), 0, 0, 0},
96 {"TlsPskEnable", store_bool, ITEM(res_main.tls_psk_enable), 0, ITEM_DEFAULT, tls_psk_default},
97 {"TlsCaCertificateFile", store_dir, ITEM(res_main.tls_ca_certfile), 0, 0, 0},
98 {"TlsCaCertificateDir", store_dir, ITEM(res_main.tls_ca_certdir), 0, 0, 0},
99 {"TlsCertificate", store_dir, ITEM(res_main.tls_certfile), 0, 0, 0},
100 {"TlsKey", store_dir, ITEM(res_main.tls_keyfile), 0, 0, 0},
101
102 {NULL, NULL, {0}, 0, 0, 0}
103 };
104
105 /*
106 * Client or File daemon resource
107 *
108 * name handler value code flags default_value
109 */
110
111 static RES_ITEM cli_items[] = {
112 {"Name", store_name, ITEM(res_main.hdr.name), 0, ITEM_REQUIRED, 0},
113 {"Description", store_str, ITEM(res_main.hdr.desc), 0, 0, 0},
114 {"Address", store_str, ITEM(res_main.address), 0, ITEM_REQUIRED, 0},
115 {"Port", store_pint32, ITEM(res_main.port), 0, ITEM_DEFAULT, 9102},
116 {"Password", store_password, ITEM(res_main.password), 0, ITEM_REQUIRED, 0},
117 {"ConnectTimeout", store_time,ITEM(res_main.connect_timeout), 0, ITEM_DEFAULT, 10},
118 {"Remote", store_bool, ITEM(res_main.use_remote), 0, ITEM_DEFAULT, 0},
119 {"Monitor", store_bool, ITEM(res_main.use_monitor), 0, ITEM_DEFAULT, 0},
120 {"Managed", store_bool, ITEM(res_main.managed), 0, ITEM_DEFAULT, 0},
121 {"TlsEnable", store_bool, ITEM(res_main.tls_enable), 0, 0, 0},
122 {"TlsPskEnable", store_bool, ITEM(res_main.tls_psk_enable), 0, ITEM_DEFAULT, tls_psk_default},
123 {"TlsCaCertificateFile", store_dir, ITEM(res_main.tls_ca_certfile), 0, 0, 0},
124 {"TlsCaCertificateDir", store_dir, ITEM(res_main.tls_ca_certdir), 0, 0, 0},
125 {"TlsCertificate", store_dir, ITEM(res_main.tls_certfile), 0, 0, 0},
126 {"TlsKey", store_dir, ITEM(res_main.tls_keyfile), 0, 0, 0},
127 {NULL, NULL, {0}, 0, 0, 0}
128 };
129
130 /* Storage daemon resource
131 *
132 * name handler value code flags default_value
133 */
134 static RES_ITEM store_items[] = {
135 {"Name", store_name, ITEM(res_main.hdr.name), 0, ITEM_REQUIRED, 0},
136 {"Description", store_str, ITEM(res_main.hdr.desc), 0, 0, 0},
137 {"Port", store_pint32, ITEM(res_main.port), 0, ITEM_DEFAULT, 9103},
138 {"Address", store_str, ITEM(res_main.address), 0, ITEM_REQUIRED, 0},
139 {"Password", store_password, ITEM(res_main.password), 0, ITEM_REQUIRED, 0},
140 {"ConnectTimeout", store_time,ITEM(res_main.connect_timeout), 0, ITEM_DEFAULT, 10},
141 {"Monitor", store_bool, ITEM(res_main.use_monitor), 0, ITEM_DEFAULT, 0},
142 {"TlsEnable", store_bool, ITEM(res_main.tls_enable), 0, 0, 0},
143 {"TlsPskEnable", store_bool, ITEM(res_main.tls_psk_enable), 0, ITEM_DEFAULT, tls_psk_default},
144 {"TlsCaCertificateFile", store_dir, ITEM(res_main.tls_ca_certfile), 0, 0, 0},
145 {"TlsCaCertificateDir", store_dir, ITEM(res_main.tls_ca_certdir), 0, 0, 0},
146 {"TlsCertificate", store_dir, ITEM(res_main.tls_certfile), 0, 0, 0},
147 {"TlsKey", store_dir, ITEM(res_main.tls_keyfile), 0, 0, 0},
148 {NULL, NULL, {0}, 0, 0, 0}
149 };
150
151 /*
152 * This is the master resource definition.
153 * It must have one item for each of the resources.
154 *
155 * NOTE!!! keep it in the same order as the R_codes
156 * or eliminate all resources[rindex].name
157 *
158 * name items rcode res_head
159 */
160 RES_TABLE resources[] = {
161 {"monitor", mon_items, R_MONITOR},
162 {"director", dir_items, R_DIRECTOR},
163 {"client", cli_items, R_CLIENT},
164 {"storage", store_items, R_STORAGE},
165 {NULL, NULL, 0}
166 };
167
168 /* Dump contents of resource */
dump_resource(int type,RES * ares,void sendit (void * sock,const char * fmt,...),void * sock)169 void dump_resource(int type, RES *ares, void sendit(void *sock, const char *fmt, ...), void *sock)
170 {
171 RES *next;
172 URES *res = (URES *)ares;
173 bool recurse = true;
174
175 if (res == NULL) {
176 sendit(sock, _("No %s resource defined\n"), res_to_str(type));
177 return;
178 }
179 if (type < 0) { /* no recursion */
180 type = - type;
181 recurse = false;
182 }
183 switch (type) {
184 case R_MONITOR:
185 sendit(sock, _("Monitor: name=%s\n"), ares->name);
186 break;
187 case R_DIRECTOR:
188 sendit(sock, _("Director: name=%s address=%s port=%d\n"),
189 res->res_main.hdr.name, res->res_main.address, res->res_main.port);
190 break;
191 case R_CLIENT:
192 sendit(sock, _("Client: name=%s address=%s port=%d\n"),
193 res->res_main.hdr.name, res->res_main.address, res->res_main.port);
194 break;
195 case R_STORAGE:
196 sendit(sock, _("Storage: name=%s address=%s port=%d\n"),
197 res->res_main.hdr.name, res->res_main.address, res->res_main.port);
198 break;
199 default:
200 sendit(sock, _("Unknown resource type %d in dump_resource.\n"), type);
201 break;
202 }
203 if (recurse) {
204 next = GetNextRes(0, (RES *)res);
205 if (next) {
206 dump_resource(type, next, sendit, sock);
207 }
208 }
209 }
210
211 /*
212 * Free memory of resource -- called when daemon terminates.
213 * NB, we don't need to worry about freeing any references
214 * to other resources as they will be freed when that
215 * resource chain is traversed. Mainly we worry about freeing
216 * allocated strings (names).
217 */
free_resource(RES * sres,int type)218 void free_resource(RES *sres, int type)
219 {
220 URES *res = (URES *)sres;
221
222 if (res == NULL)
223 return;
224 /* common stuff -- free the resource name and description */
225 if (res->res_monitor.hdr.name) {
226 free(res->res_monitor.hdr.name);
227 }
228 if (res->res_monitor.hdr.desc) {
229 free(res->res_monitor.hdr.desc);
230 }
231
232 switch (type) {
233 case R_MONITOR:
234 if (res->res_monitor.password) {
235 free(res->res_monitor.password);
236 }
237 if (res->res_monitor.command_dir) {
238 free(res->res_monitor.command_dir);
239 }
240 break;
241 case R_DIRECTOR:
242 case R_CLIENT:
243 case R_STORAGE:
244 delete res->res_main.mutex;
245 free_bsock(res->res_main.bs);
246 if (res->res_main.wrk) {
247 worker_stop(res->res_main.wrk);
248 res->res_main.wrk = NULL;
249 }
250 if (res->res_main.address) {
251 free(res->res_main.address);
252 }
253 if (res->res_main.tls_ctx) {
254 free_tls_context(res->res_main.tls_ctx);
255 }
256 if (res->res_main.tls_ca_certfile) {
257 free(res->res_main.tls_ca_certfile);
258 }
259 if (res->res_main.tls_ca_certdir) {
260 free(res->res_main.tls_ca_certdir);
261 }
262 if (res->res_main.tls_certfile) {
263 free(res->res_main.tls_certfile);
264 }
265 if (res->res_main.tls_keyfile) {
266 free(res->res_main.tls_keyfile);
267 }
268 if (res->res_main.jobs) {
269 delete res->res_main.jobs;
270 }
271 if (res->res_main.clients) {
272 delete res->res_main.clients;
273 }
274 if (res->res_main.filesets) {
275 delete res->res_main.filesets;
276 }
277 if (res->res_main.pools) {
278 delete res->res_main.pools;
279 }
280 if (res->res_main.storages) {
281 delete res->res_main.storages;
282 }
283 if (res->res_main.running_jobs) {
284 delete res->res_main.terminated_jobs;
285 }
286 break;
287 default:
288 printf(_("Unknown resource type %d in free_resource.\n"), type);
289 }
290
291 /* Common stuff again -- free the resource, recurse to next one */
292 if (res) {
293 free(res);
294 }
295 }
296
297 /*
298 * Save the new resource by chaining it into the head list for
299 * the resource. If this is pass 2, we update any resource
300 * pointers because they may not have been defined until
301 * later in pass 1.
302 */
save_resource(CONFIG * config,int type,RES_ITEM * items,int pass)303 bool save_resource(CONFIG *config, int type, RES_ITEM *items, int pass)
304 {
305 int rindex = type - r_first;
306 int i, size;
307 int error = 0;
308
309 /*
310 * Ensure that all required items are present
311 */
312 for (i=0; items[i].name; i++) {
313 if (items[i].flags & ITEM_REQUIRED) {
314 if (!bit_is_set(i, res_all.res_monitor.hdr.item_present)) {
315 Mmsg(config->m_errmsg, _("\"%s\" directive is required in \"%s\" resource, but not found.\n"),
316 items[i].name, resources[rindex].name);
317 return false;
318 }
319 }
320 /* If this triggers, take a look at lib/parse_conf.h */
321 if (i >= MAX_RES_ITEMS) {
322 Mmsg(config->m_errmsg, _("Too many directives in \"%s\" resource\n"), resources[rindex].name);
323 return false;
324 }
325 }
326
327 /*
328 * During pass 2 in each "store" routine, we looked up pointers
329 * to all the resources referrenced in the current resource, now we
330 * must copy their addresses from the static record to the allocated
331 * record.
332 */
333 if (pass == 2) {
334 switch (type) {
335 /* Resources not containing a resource */
336 case R_STORAGE:
337 case R_DIRECTOR:
338 case R_CLIENT:
339 case R_MONITOR:
340 break;
341 default:
342 Emsg1(M_ERROR, 0, _("Unknown resource type %d in save_resource.\n"), type);
343 error = 1;
344 break;
345 }
346 /* Note, the resource name was already saved during pass 1,
347 * so here, we can just release it.
348 */
349 if (res_all.res_monitor.hdr.name) {
350 free(res_all.res_monitor.hdr.name);
351 res_all.res_monitor.hdr.name = NULL;
352 }
353 if (res_all.res_monitor.hdr.desc) {
354 free(res_all.res_monitor.hdr.desc);
355 res_all.res_monitor.hdr.desc = NULL;
356 }
357 return true;
358 }
359
360 /*
361 * The following code is only executed during pass 1
362 */
363 switch (type) {
364 case R_MONITOR:
365 size = sizeof(MONITOR);
366 break;
367 case R_CLIENT:
368 case R_STORAGE:
369 case R_DIRECTOR:
370 // We need to initialize the mutex
371 res_all.res_main.mutex = new QMutex();
372 res_all.res_main.wrk = worker_start();
373 size = sizeof(RESMON);
374 break;
375 default:
376 printf(_("Unknown resource type %d in save_resource.\n"), type);
377 error = 1;
378 size = 1;
379 break;
380 }
381 /* Common */
382 if (!error) {
383 res_all.res_main.type = type;
384 if (!config->insert_res(rindex, size)) {
385 return false;
386 }
387 }
388 return true;
389 }
390
parse_tmon_config(CONFIG * config,const char * configfile,int exit_code)391 bool parse_tmon_config(CONFIG *config, const char *configfile, int exit_code)
392 {
393 config->init(configfile, error_handler, exit_code,
394 (void *)&res_all, res_all_size,
395 r_first, r_last, resources, &res_head);
396 return config->parse_config();
397 }
398