1 /*
2 BAREOS® - Backup Archiving REcovery Open Sourced
3
4 Copyright (C) 2004-2011 Free Software Foundation Europe e.V.
5 Copyright (C) 2011-2012 Planets Communications B.V.
6 Copyright (C) 2013-2020 Bareos GmbH & Co. KG
7
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
11 in the file LICENSE.
12
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 Affero General Public License for more details.
17
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
21 02110-1301, USA.
22 */
23 /*
24 * Main configuration file parser for Bareos Tray Monitor.
25 * Adapted from dird_conf.c
26 *
27 * Note, the configuration file parser consists of three parts
28 *
29 * 1. The generic lexical scanner in lib/lex.c and lib/lex.h
30 *
31 * 2. The generic config scanner in lib/parse_config.c and
32 * lib/parse_config.h. These files contain the parser code,
33 * some utility routines, and the common store routines
34 * (name, int, string).
35 *
36 * 3. The daemon specific file, which contains the Resource
37 * definitions as well as any specific store routines
38 * for the resource records.
39 *
40 * Nicolas Boichat, August MMIV
41 */
42
43 #include "include/bareos.h"
44 #define NEED_JANSSON_NAMESPACE 1
45 #include "lib/output_formatter.h"
46 #include "tray_conf.h"
47
48 #include "lib/parse_conf.h"
49 #include "lib/resource_item.h"
50 #include "lib/tls_resource_items.h"
51 #include "lib/output_formatter.h"
52 #include "lib/output_formatter_resource.h"
53
54 #include <cassert>
55
56 static const std::string default_config_filename("tray-monitor.conf");
57
58 static BareosResource* sres_head[R_LAST - R_FIRST + 1];
59 static BareosResource** res_head = sres_head;
60
61 static bool SaveResource(int type, ResourceItem* items, int pass);
62 static void FreeResource(BareosResource* sres, int type);
63 static void DumpResource(int type,
64 BareosResource* reshdr,
65 bool sendit(void* sock, const char* fmt, ...),
66 void* sock,
67 bool hide_sensitive_data,
68 bool verbose);
69 /*
70 * We build the current resource here as we are
71 * scanning the resource configuration definition,
72 * then move it to allocated memory when the resource
73 * scan is complete.
74 */
75 static MonitorResource* res_monitor;
76 static DirectorResource* res_dir;
77 static ClientResource* res_client;
78 static StorageResource* res_store;
79 static ConsoleFontResource* res_font;
80
81 /* clang-format off */
82
83 /*
84 * Monitor Resource
85 *
86 * name handler value code flags default_value
87 */
88 static ResourceItem mon_items[] = {
89 {"Name", CFG_TYPE_NAME, ITEM(res_monitor,resource_name_), 0, CFG_ITEM_REQUIRED, 0, NULL, NULL},
90 {"Description", CFG_TYPE_STR, ITEM(res_monitor,description_), 0, 0, 0, NULL, NULL},
91 {"Password", CFG_TYPE_MD5PASSWORD, ITEM(res_monitor,password), 0, CFG_ITEM_REQUIRED, NULL, NULL, NULL},
92 {"RefreshInterval", CFG_TYPE_TIME, ITEM(res_monitor,RefreshInterval), 0, CFG_ITEM_DEFAULT, "60", NULL, NULL},
93 {"FdConnectTimeout", CFG_TYPE_TIME, ITEM(res_monitor,FDConnectTimeout), 0, CFG_ITEM_DEFAULT, "10", NULL, NULL},
94 {"SdConnectTimeout", CFG_TYPE_TIME, ITEM(res_monitor,SDConnectTimeout), 0, CFG_ITEM_DEFAULT, "10", NULL, NULL},
95 {"DirConnectTimeout", CFG_TYPE_TIME, ITEM(res_monitor,DIRConnectTimeout), 0, CFG_ITEM_DEFAULT, "10", NULL, NULL},
96 TLS_COMMON_CONFIG(res_monitor),
97 TLS_CERT_CONFIG(res_monitor),
98 {nullptr, 0, 0, nullptr, 0, 0, nullptr, nullptr, nullptr}
99 };
100
101 /*
102 * Director's that we can contact
103 *
104 * name handler value code flags default_value
105 */
106 static ResourceItem dir_items[] = {
107 {"Name", CFG_TYPE_NAME, ITEM(res_dir,resource_name_), 0, CFG_ITEM_REQUIRED, NULL, NULL, NULL},
108 {"Description", CFG_TYPE_STR, ITEM(res_dir,description_), 0, 0, NULL, NULL, NULL},
109 {"DirPort", CFG_TYPE_PINT32, ITEM(res_dir,DIRport), 0, CFG_ITEM_DEFAULT, DIR_DEFAULT_PORT, NULL, NULL},
110 {"Address", CFG_TYPE_STR, ITEM(res_dir,address), 0, CFG_ITEM_REQUIRED, NULL, NULL, NULL},
111 TLS_COMMON_CONFIG(res_dir),
112 TLS_CERT_CONFIG(res_dir),
113 {nullptr, 0, 0, nullptr, 0, 0, nullptr, nullptr, nullptr}
114 };
115
116 /*
117 * Client or File daemon resource
118 *
119 * name handler value code flags default_value
120 */
121 static ResourceItem cli_items[] = {
122 {"Name", CFG_TYPE_NAME, ITEM(res_client,resource_name_), 0, CFG_ITEM_REQUIRED, NULL, NULL, NULL},
123 {"Description", CFG_TYPE_STR, ITEM(res_client,description_), 0, 0, NULL, NULL, NULL},
124 {"Address", CFG_TYPE_STR, ITEM(res_client,address), 0, CFG_ITEM_REQUIRED, NULL, NULL, NULL},
125 {"FdPort", CFG_TYPE_PINT32, ITEM(res_client,FDport), 0, CFG_ITEM_DEFAULT, FD_DEFAULT_PORT, NULL, NULL},
126 {"Password", CFG_TYPE_MD5PASSWORD, ITEM(res_client,password), 0, CFG_ITEM_REQUIRED, NULL, NULL, NULL},
127 TLS_COMMON_CONFIG(res_client),
128 TLS_CERT_CONFIG(res_client),
129 {nullptr, 0, 0, nullptr, 0, 0, nullptr, nullptr, nullptr}
130 };
131
132 /*
133 * Storage daemon resource
134 *
135 * name handler value code flags default_value
136 */
137 static ResourceItem store_items[] = {
138 {"Name", CFG_TYPE_NAME, ITEM(res_store,resource_name_), 0, CFG_ITEM_REQUIRED, NULL, NULL, NULL},
139 {"Description", CFG_TYPE_STR, ITEM(res_store,description_), 0, 0, NULL, NULL, NULL},
140 {"SdPort", CFG_TYPE_PINT32, ITEM(res_store,SDport), 0, CFG_ITEM_DEFAULT, SD_DEFAULT_PORT, NULL, NULL},
141 {"Address", CFG_TYPE_STR, ITEM(res_store,address), 0, CFG_ITEM_REQUIRED, NULL, NULL, NULL},
142 {"SdAddress", CFG_TYPE_STR, ITEM(res_store,address), 0, 0, NULL, NULL, NULL},
143 {"Password", CFG_TYPE_MD5PASSWORD, ITEM(res_store,password), 0, CFG_ITEM_REQUIRED, NULL, NULL, NULL},
144 {"SdPassword", CFG_TYPE_MD5PASSWORD, ITEM(res_store,password), 0, 0, NULL, NULL, NULL},
145 TLS_COMMON_CONFIG(res_store),
146 TLS_CERT_CONFIG(res_store),
147 {nullptr, 0, 0, nullptr, 0, 0, nullptr, nullptr, nullptr}
148 };
149
150 /*
151 * Font resource
152 *
153 * name handler value code flags default_value
154 */
155 static ResourceItem con_font_items[] = {
156 {"Name", CFG_TYPE_NAME, ITEM(res_font,resource_name_), 0, CFG_ITEM_REQUIRED, NULL, NULL, NULL},
157 {"Description", CFG_TYPE_STR, ITEM(res_font,description_), 0, 0, NULL, NULL, NULL},
158 {"Font", CFG_TYPE_STR, ITEM(res_font,fontface), 0, 0, NULL, NULL, NULL},
159 {nullptr, 0, 0, nullptr, 0, 0, nullptr, nullptr, nullptr}
160 };
161
162 /*
163 * This is the master resource definition.
164 * It must have one item for each of the resources.
165 *
166 * NOTE!!! keep it in the same order as the R_codes
167 * or eliminate all resources[rindex].name
168 *
169 * name items rcode res_head
170 */
171 static ResourceTable resources[] = {
172 {"Monitor", "Monitors", mon_items, R_MONITOR, sizeof(MonitorResource),
__anon8c058a970102() 173 []() { res_monitor = new MonitorResource(); }, reinterpret_cast<BareosResource**>(&res_monitor)},
174 {"Director", "Directors", dir_items, R_DIRECTOR, sizeof(DirectorResource),
__anon8c058a970202() 175 []() { res_dir = new DirectorResource(); }, reinterpret_cast<BareosResource**>(&res_dir)},
176 {"Client", "Clients", cli_items, R_CLIENT, sizeof(ClientResource),
__anon8c058a970302() 177 []() { res_client = new ClientResource(); }, reinterpret_cast<BareosResource**>(&res_client)},
178 {"Storage", "Storages", store_items, R_STORAGE, sizeof(StorageResource),
__anon8c058a970402() 179 []() { res_store = new StorageResource(); }, reinterpret_cast<BareosResource**>(&res_store)},
180 {"ConsoleFont", "ConsoleFonts", con_font_items, R_CONSOLE_FONT, sizeof(ConsoleFontResource),
__anon8c058a970502() 181 []() { res_font = new ConsoleFontResource(); }, reinterpret_cast<BareosResource**>(&res_font)},
182 {nullptr, nullptr, nullptr, 0, 0, nullptr, nullptr}
183 };
184
185 /* clang-format on */
186
187 /*
188 * Dump contents of resource
189 */
DumpResource(int type,BareosResource * res,bool sendit (void * sock,const char * fmt,...),void * sock,bool hide_sensitive_data,bool verbose)190 static void DumpResource(int type,
191 BareosResource* res,
192 bool sendit(void* sock, const char* fmt, ...),
193 void* sock,
194 bool hide_sensitive_data,
195 bool verbose)
196 {
197 PoolMem buf;
198 bool recurse = true;
199 OutputFormatter output_formatter
200 = OutputFormatter(sendit, sock, nullptr, nullptr);
201 OutputFormatterResource output_formatter_resource
202 = OutputFormatterResource(&output_formatter);
203
204 if (res == NULL) {
205 sendit(sock, _("Warning: no \"%s\" resource (%d) defined.\n"),
206 my_config->ResToStr(type), type);
207 return;
208 }
209 if (type < 0) { /* no recursion */
210 type = -type;
211 recurse = false;
212 }
213 switch (type) {
214 default:
215 res->PrintConfig(output_formatter_resource, *my_config,
216 hide_sensitive_data, verbose);
217 break;
218 }
219 sendit(sock, "%s", buf.c_str());
220
221 if (recurse && res->next_) {
222 DumpResource(type, res->next_, sendit, sock, hide_sensitive_data, verbose);
223 }
224 }
225
FreeResource(BareosResource * res,int type)226 static void FreeResource(BareosResource* res, int type)
227 {
228 if (res == NULL) return;
229
230 BareosResource* next_resource = (BareosResource*)res->next_;
231
232 if (res->resource_name_) { free(res->resource_name_); }
233 if (res->description_) { free(res->description_); }
234
235 switch (type) {
236 case R_MONITOR:
237 break;
238 case R_DIRECTOR: {
239 DirectorResource* p = dynamic_cast<DirectorResource*>(res);
240 assert(p);
241 if (p->address) { free(p->address); }
242 break;
243 }
244 case R_CLIENT: {
245 ClientResource* p = dynamic_cast<ClientResource*>(res);
246 assert(p);
247 if (p->address) { free(p->address); }
248 if (p->password.value) { free(p->password.value); }
249 break;
250 }
251 case R_STORAGE: {
252 StorageResource* p = dynamic_cast<StorageResource*>(res);
253 assert(p);
254 if (p->address) { free(p->address); }
255 if (p->password.value) { free(p->password.value); }
256 break;
257 }
258 case R_CONSOLE_FONT: {
259 ConsoleFontResource* p = dynamic_cast<ConsoleFontResource*>(res);
260 assert(p);
261 if (p->fontface) { free(p->fontface); }
262 break;
263 }
264 default:
265 printf(_("Unknown resource type %d in FreeResource.\n"), type);
266 break;
267 }
268
269 if (next_resource) { FreeResource(next_resource, type); }
270 }
271
272 /*
273 * Save the new resource by chaining it into the head list for
274 * the resource. If this is pass 2, we update any resource
275 * pointers because they may not have been defined until
276 * later in pass 1.
277 */
SaveResource(int type,ResourceItem * items,int pass)278 static bool SaveResource(int type, ResourceItem* items, int pass)
279 {
280 int rindex = type - R_FIRST;
281 int i;
282 int error = 0;
283
284 /*
285 * Ensure that all required items are present
286 */
287 for (i = 0; items[i].name; i++) {
288 if (items[i].flags & CFG_ITEM_REQUIRED) {
289 if (!BitIsSet(i, (*items[i].allocated_resource)->item_present_)) {
290 Emsg2(M_ERROR_TERM, 0,
291 _("%s item is required in %s resource, but not found.\n"),
292 items[i].name, resources[rindex].name);
293 }
294 }
295 /* If this triggers, take a look at lib/parse_conf.h */
296 if (i >= MAX_RES_ITEMS) {
297 Emsg1(M_ERROR_TERM, 0, _("Too many items in %s resource\n"),
298 resources[rindex].name);
299 }
300 }
301
302 /*
303 * During pass 2 in each "store" routine, we looked up pointers
304 * to all the resources referrenced in the current resource, now we
305 * must copy their addresses from the static record to the allocated
306 * record.
307 */
308 if (pass == 2) {
309 switch (type) {
310 case R_MONITOR:
311 case R_CLIENT:
312 case R_STORAGE:
313 case R_DIRECTOR:
314 case R_CONSOLE_FONT:
315 // Resources not containing a resource
316 break;
317 default:
318 Emsg1(M_ERROR, 0, _("Unknown resource type %d in SaveResource.\n"),
319 type);
320 error = 1;
321 break;
322 }
323
324 /* resource_name_ was already deep copied during 1. pass
325 * as matter of fact the remaining allocated memory is
326 * redundant and would not be freed in the dynamic resources;
327 *
328 * currently, this is the best place to free that */
329
330 BareosResource* res = *items[0].allocated_resource;
331
332 if (res) {
333 if (res->resource_name_) {
334 free(res->resource_name_);
335 res->resource_name_ = nullptr;
336 }
337 if (res->description_) {
338 free(res->description_);
339 res->description_ = nullptr;
340 }
341 }
342 return (error == 0);
343 }
344
345 if (!error) {
346 BareosResource* new_resource = nullptr;
347 switch (type) {
348 case R_MONITOR:
349 new_resource = res_monitor;
350 res_monitor = nullptr;
351 break;
352 case R_CLIENT:
353 new_resource = res_client;
354 res_client = nullptr;
355 break;
356 case R_STORAGE:
357 new_resource = res_store;
358 res_store = nullptr;
359 break;
360 case R_DIRECTOR:
361 new_resource = res_dir;
362 res_dir = nullptr;
363 break;
364 case R_CONSOLE_FONT:
365 new_resource = res_font;
366 res_font = nullptr;
367 break;
368 default:
369 ASSERT(false);
370 break;
371 }
372 error = my_config->AppendToResourcesChain(new_resource, type) ? 0 : 1;
373 }
374 return (error == 0);
375 }
376
ConfigBeforeCallback(ConfigurationParser & my_config)377 static void ConfigBeforeCallback(ConfigurationParser& my_config)
378 {
379 std::map<int, std::string> map{
380 {R_MONITOR, "R_MONITOR"}, {R_DIRECTOR, "R_DIRECTOR"},
381 {R_CLIENT, "R_CLIENT"}, {R_STORAGE, "R_STORAGE"},
382 {R_CONSOLE, "R_CONSOLE"}, {R_CONSOLE_FONT, "R_CONSOLE_FONT"}};
383 my_config.InitializeQualifiedResourceNameTypeConverter(map);
384 }
385
ConfigReadyCallback(ConfigurationParser & my_config)386 static void ConfigReadyCallback(ConfigurationParser& my_config) {}
387
InitTmonConfig(const char * configfile,int exit_code)388 ConfigurationParser* InitTmonConfig(const char* configfile, int exit_code)
389 {
390 ConfigurationParser* config = new ConfigurationParser(
391 configfile, nullptr, nullptr, nullptr, nullptr, nullptr, exit_code,
392 R_FIRST, R_LAST, resources, res_head, default_config_filename.c_str(),
393 "tray-monitor.d", ConfigBeforeCallback, ConfigReadyCallback, SaveResource,
394 DumpResource, FreeResource);
395 if (config) { config->r_own_ = R_MONITOR; }
396 return config;
397 }
398
399 /*
400 * Print configuration file schema in json format
401 */
402 #ifdef HAVE_JANSSON
PrintConfigSchemaJson(PoolMem & buffer)403 bool PrintConfigSchemaJson(PoolMem& buffer)
404 {
405 ResourceTable* resources = my_config->resources_;
406
407 InitializeJson();
408
409 json_t* json = json_object();
410 json_object_set_new(json, "format-version", json_integer(2));
411 json_object_set_new(json, "component", json_string("bareos-tray-monitor"));
412 json_object_set_new(json, "version", json_string(kBareosVersionStrings.Full));
413
414 /*
415 * Resources
416 */
417 json_t* resource = json_object();
418 json_object_set(json, "resource", resource);
419 json_t* bareos_tray_monitor = json_object();
420 json_object_set(resource, "bareos-tray-monitor", bareos_tray_monitor);
421
422 for (int r = 0; resources[r].name; r++) {
423 ResourceTable resource = my_config->resources_[r];
424 json_object_set(bareos_tray_monitor, resource.name,
425 json_items(resource.items));
426 }
427
428 PmStrcat(buffer, json_dumps(json, JSON_INDENT(2)));
429 json_decref(json);
430
431 return true;
432 }
433 #else
PrintConfigSchemaJson(PoolMem & buffer)434 bool PrintConfigSchemaJson(PoolMem& buffer)
435 {
436 PmStrcat(buffer, "{ \"success\": false, \"message\": \"not available\" }");
437 return false;
438 }
439 #endif
440