1 /*
2 BAREOS® - Backup Archiving REcovery Open Sourced
3
4 Copyright (C) 2000-2011 Free Software Foundation Europe e.V.
5 Copyright (C) 2013-2020 Bareos GmbH & Co. KG
6
7 This program is Free Software; you can redistribute it and/or
8 modify it under the terms of version three of the GNU Affero General Public
9 License as published by the Free Software Foundation and included
10 in the file LICENSE.
11
12 This program is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Affero General Public License for more details.
16
17 You should have received a copy of the GNU Affero General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 02110-1301, USA.
21 */
22 /*
23 * This file handles most things related to generic resources.
24 *
25 * Kern Sibbald, January MM
26 * Split from parse_conf.c April MMV
27 */
28
29 #define NEED_JANSSON_NAMESPACE 1
30 #include "include/bareos.h"
31 #include "generic_res.h"
32 #include "lib/edit.h"
33 #include "include/jcr.h"
34 #include "qualified_resource_name_type_converter.h"
35 #include "lib/parse_conf.h"
36 #include "lib/messages_resource.h"
37 #include "lib/output_formatter_resource.h"
38 #include "lib/resource_item.h"
39 #include "lib/util.h"
40 #include "lib/address_conf.h"
41 #include "lib/output_formatter.h"
42
43 /*
44 * Set default indention e.g. 2 spaces.
45 */
46 #define DEFAULT_INDENT_STRING " "
47
48 static int res_locked = 0; /* resource chain lock count -- for debug */
49
50 // #define TRACE_RES
51
b_LockRes(const char * file,int line) const52 void ConfigurationParser::b_LockRes(const char* file, int line) const
53 {
54 int errstat;
55
56 #ifdef TRACE_RES
57 char ed1[50];
58
59 Pmsg4(000, "LockRes locked=%d w_active=%d at %s:%d\n", res_locked,
60 res_lock_.w_active, file, line);
61
62 if (res_locked) {
63 Pmsg2(000, "LockRes writerid=%lu myid=%s\n", res_lock_.writer_id,
64 edit_pthread(pthread_self(), ed1, sizeof(ed1)));
65 }
66 #endif
67
68 if ((errstat = RwlWritelock(&res_lock_)) != 0) {
69 Emsg3(M_ABORT, 0, _("RwlWritelock failure at %s:%d: ERR=%s\n"), file, line,
70 strerror(errstat));
71 }
72
73 res_locked++;
74 }
75
b_UnlockRes(const char * file,int line) const76 void ConfigurationParser::b_UnlockRes(const char* file, int line) const
77 {
78 int errstat;
79
80 if ((errstat = RwlWriteunlock(&res_lock_)) != 0) {
81 Emsg3(M_ABORT, 0, _("RwlWriteunlock failure at %s:%d:. ERR=%s\n"), file,
82 line, strerror(errstat));
83 }
84 res_locked--;
85 #ifdef TRACE_RES
86 Pmsg4(000, "UnLockRes locked=%d wactive=%d at %s:%d\n", res_locked,
87 res_lock_.w_active, file, line);
88 #endif
89 }
90
91 /*
92 * Return resource of type rcode that matches name
93 */
GetResWithName(int rcode,const char * name,bool lock) const94 BareosResource* ConfigurationParser::GetResWithName(int rcode,
95 const char* name,
96 bool lock) const
97 {
98 BareosResource* res;
99 int rindex = rcode - r_first_;
100
101 if (lock) { LockRes(this); }
102
103 res = res_head_[rindex];
104 while (res) {
105 if (bstrcmp(res->resource_name_, name)) { break; }
106 res = res->next_;
107 }
108
109 if (lock) { UnlockRes(this); }
110
111 return res;
112 }
113
114 /*
115 * Return next resource of type rcode. On first
116 * call second arg (res) is NULL, on subsequent
117 * calls, it is called with previous value.
118 */
GetNextRes(int rcode,BareosResource * res) const119 BareosResource* ConfigurationParser::GetNextRes(int rcode,
120 BareosResource* res) const
121 {
122 BareosResource* nres;
123 int rindex = rcode - r_first_;
124
125 if (res == NULL) {
126 nres = res_head_[rindex];
127 } else {
128 nres = res->next_;
129 }
130
131 return nres;
132 }
133
ResToStr(int rcode) const134 const char* ConfigurationParser::ResToStr(int rcode) const
135 {
136 if (rcode < r_first_ || rcode > r_last_) {
137 return _("***UNKNOWN***");
138 } else {
139 return resources_[rcode - r_first_].name;
140 }
141 }
142
ResGroupToStr(int rcode) const143 const char* ConfigurationParser::ResGroupToStr(int rcode) const
144 {
145 if (rcode < r_first_ || rcode > r_last_) {
146 return _("***UNKNOWN***");
147 } else {
148 return resources_[rcode - r_first_].groupname;
149 }
150 }
151
GetTlsPskByFullyQualifiedResourceName(ConfigurationParser * config,const char * fq_name_in,std::string & psk)152 bool ConfigurationParser::GetTlsPskByFullyQualifiedResourceName(
153 ConfigurationParser* config,
154 const char* fq_name_in,
155 std::string& psk)
156 {
157 char* fq_name_buffer = strdup(fq_name_in);
158 UnbashSpaces(fq_name_buffer);
159 std::string fq_name(fq_name_buffer);
160 free(fq_name_buffer);
161
162 QualifiedResourceNameTypeConverter* c
163 = config->GetQualifiedResourceNameTypeConverter();
164 if (!c) { return false; }
165
166 int r_type;
167 std::string name; /* either unique job name or client name */
168
169 bool ok = c->StringToResource(name, r_type, fq_name_in);
170 if (!ok) { return false; }
171
172 if (fq_name.find("R_JOB") != std::string::npos) {
173 const char* psk_cstr = JcrGetAuthenticateKey(name.c_str());
174 if (psk_cstr) {
175 psk = psk_cstr;
176 return true;
177 }
178 } else {
179 TlsResource* tls = dynamic_cast<TlsResource*>(
180 config->GetResWithName(r_type, name.c_str()));
181 if (tls) {
182 psk = tls->password_.value;
183 return true;
184 } else {
185 Dmsg1(100, "Could not get tls resource for %d.\n", r_type);
186 }
187 }
188 return false;
189 }
190
191 /*
192 * Scan for message types and add them to the message
193 * destination. The basic job here is to connect message types
194 * (WARNING, ERROR, FATAL, INFO, ...) with an appropriate
195 * destination (MAIL, FILE, OPERATOR, ...)
196 */
ScanTypes(LEX * lc,MessagesResource * msg,MessageDestinationCode dest_code,const std::string & where,const std::string & cmd,const std::string & timestamp_format)197 void ConfigurationParser::ScanTypes(LEX* lc,
198 MessagesResource* msg,
199 MessageDestinationCode dest_code,
200 const std::string& where,
201 const std::string& cmd,
202 const std::string& timestamp_format)
203 {
204 int i;
205 bool found, is_not;
206 int msg_type = 0;
207 char* str;
208
209 for (;;) {
210 LexGetToken(lc, BCT_NAME); /* expect at least one type */
211 found = false;
212 if (lc->str[0] == '!') {
213 is_not = true;
214 str = &lc->str[1];
215 } else {
216 is_not = false;
217 str = &lc->str[0];
218 }
219 for (i = 0; msg_types[i].name; i++) {
220 if (Bstrcasecmp(str, msg_types[i].name)) {
221 msg_type = msg_types[i].token;
222 found = true;
223 break;
224 }
225 }
226 if (!found) {
227 scan_err1(lc, _("message type: %s not found"), str);
228 return;
229 }
230
231 if (msg_type == M_MAX + 1) { /* all? */
232 for (i = 1; i <= M_MAX; i++) { /* yes set all types */
233 msg->AddMessageDestination(dest_code, i, where, cmd, timestamp_format);
234 }
235 } else if (is_not) {
236 msg->RemoveMessageDestination(dest_code, msg_type, where);
237 } else {
238 msg->AddMessageDestination(dest_code, msg_type, where, cmd,
239 timestamp_format);
240 }
241 if (lc->ch != ',') { break; }
242 Dmsg0(900, "call LexGetToken() to eat comma\n");
243 LexGetToken(lc, BCT_ALL); /* eat comma */
244 }
245 Dmsg0(900, "Done ScanTypes()\n");
246 }
247
248 /*
249 * Store Messages Destination information
250 */
StoreMsgs(LEX * lc,ResourceItem * item,int index,int pass)251 void ConfigurationParser::StoreMsgs(LEX* lc,
252 ResourceItem* item,
253 int index,
254 int pass)
255 {
256 int token;
257 const char* cmd = nullptr;
258 POOLMEM* dest;
259 int dest_len;
260
261 Dmsg2(900, "StoreMsgs pass=%d code=%d\n", pass, item->code);
262
263 MessagesResource* message_resource
264 = dynamic_cast<MessagesResource*>(*item->allocated_resource);
265
266 if (!message_resource) {
267 Dmsg0(900, "Could not dynamic_cast to MessageResource\n");
268 abort();
269 return;
270 }
271
272 if (pass == 1) {
273 switch (static_cast<MessageDestinationCode>(item->code)) {
274 case MessageDestinationCode::kStdout:
275 case MessageDestinationCode::kStderr:
276 case MessageDestinationCode::kConsole:
277 case MessageDestinationCode::kCatalog:
278 ScanTypes(lc, message_resource,
279 static_cast<MessageDestinationCode>(item->code),
280 std::string(), std::string(),
281 message_resource->timestamp_format_);
282 break;
283 case MessageDestinationCode::kSyslog: { /* syslog */
284 char* p;
285 int cnt = 0;
286 bool done = false;
287
288 /*
289 * See if this is an old style syslog definition.
290 * We count the number of = signs in the current config line.
291 */
292 p = lc->line;
293 while (!done && *p) {
294 switch (*p) {
295 case '=':
296 cnt++;
297 break;
298 case ',':
299 case ';':
300 /*
301 * No need to continue scanning when we encounter a ',' or ';'
302 */
303 done = true;
304 break;
305 default:
306 break;
307 }
308 p++;
309 }
310
311 /*
312 * If there is more then one = its the new format e.g.
313 * syslog = facility = filter
314 */
315 if (cnt > 1) {
316 dest = GetPoolMemory(PM_MESSAGE);
317 /*
318 * Pick up a single facility.
319 */
320 token = LexGetToken(lc, BCT_NAME); /* Scan destination */
321 PmStrcpy(dest, lc->str);
322 dest_len = lc->str_len;
323 token = LexGetToken(lc, BCT_SKIP_EOL);
324
325 ScanTypes(lc, message_resource,
326 static_cast<MessageDestinationCode>(item->code), dest,
327 std::string(), std::string());
328 FreePoolMemory(dest);
329 Dmsg0(900, "done with dest codes\n");
330 } else {
331 ScanTypes(lc, message_resource,
332 static_cast<MessageDestinationCode>(item->code),
333 std::string(), std::string(), std::string());
334 }
335 break;
336 }
337 case MessageDestinationCode::kOperator:
338 case MessageDestinationCode::kDirector:
339 case MessageDestinationCode::kMail:
340 case MessageDestinationCode::KMailOnError:
341 case MessageDestinationCode::kMailOnSuccess:
342 if (static_cast<MessageDestinationCode>(item->code)
343 == MessageDestinationCode::kOperator) {
344 cmd = message_resource->operator_cmd_.c_str();
345 } else {
346 cmd = message_resource->mail_cmd_.c_str();
347 }
348 dest = GetPoolMemory(PM_MESSAGE);
349 dest[0] = 0;
350 dest_len = 0;
351
352 /*
353 * Pick up comma separated list of destinations.
354 */
355 for (;;) {
356 token = LexGetToken(lc, BCT_NAME); /* Scan destination */
357 dest = CheckPoolMemorySize(dest, dest_len + lc->str_len + 2);
358 if (dest[0] != 0) {
359 PmStrcat(dest, " "); /* Separate multiple destinations with space */
360 dest_len++;
361 }
362 PmStrcat(dest, lc->str);
363 dest_len += lc->str_len;
364 Dmsg2(900, "StoreMsgs newdest=%s: dest=%s:\n", lc->str, NPRT(dest));
365 token = LexGetToken(lc, BCT_SKIP_EOL);
366 if (token == BCT_COMMA) { continue; /* Get another destination */ }
367 if (token != BCT_EQUALS) {
368 scan_err1(lc, _("expected an =, got: %s"), lc->str);
369 return;
370 }
371 break;
372 }
373 Dmsg1(900, "mail_cmd=%s\n", NPRT(cmd));
374 ScanTypes(lc, message_resource,
375 static_cast<MessageDestinationCode>(item->code), dest, cmd,
376 message_resource->timestamp_format_);
377 FreePoolMemory(dest);
378 Dmsg0(900, "done with dest codes\n");
379 break;
380 case MessageDestinationCode::kFile:
381 case MessageDestinationCode::kAppend: {
382 /*
383 * Pick up a single destination.
384 */
385 token = LexGetToken(lc, BCT_STRING); /* Scan destination */
386 std::string dest_file_path(lc->str);
387 dest_len = lc->str_len;
388 token = LexGetToken(lc, BCT_SKIP_EOL);
389 Dmsg1(900, "StoreMsgs dest=%s:\n", dest_file_path.c_str());
390 if (token != BCT_EQUALS) {
391 scan_err1(lc, _("expected an =, got: %s"), lc->str);
392 return;
393 }
394 ScanTypes(lc, message_resource,
395 static_cast<MessageDestinationCode>(item->code),
396 dest_file_path, std::string(),
397 message_resource->timestamp_format_);
398 Dmsg0(900, "done with dest codes\n");
399 break;
400 }
401 default:
402 scan_err1(lc, _("Unknown item code: %d\n"), item->code);
403 return;
404 }
405 }
406 ScanToEol(lc);
407 SetBit(index, message_resource->item_present_);
408 ClearBit(index, message_resource->inherit_content_);
409 Dmsg0(900, "Done StoreMsgs\n");
410 }
411
412 /*
413 * This routine is ONLY for resource names
414 * Store a name at specified address.
415 */
StoreName(LEX * lc,ResourceItem * item,int index,int pass)416 void ConfigurationParser::StoreName(LEX* lc,
417 ResourceItem* item,
418 int index,
419 int pass)
420 {
421 POOLMEM* msg = GetPoolMemory(PM_EMSG);
422
423 LexGetToken(lc, BCT_NAME);
424 if (!IsNameValid(lc->str, msg)) {
425 scan_err1(lc, "%s\n", msg);
426 return;
427 }
428 FreePoolMemory(msg);
429 /*
430 * Store the name both in pass 1 and pass 2
431 */
432 char** p = GetItemVariablePointer<char**>(*item);
433
434 if (*p) {
435 scan_err2(lc, _("Attempt to redefine name \"%s\" to \"%s\"."), *p, lc->str);
436 return;
437 }
438 *p = strdup(lc->str);
439 ScanToEol(lc);
440 SetBit(index, (*item->allocated_resource)->item_present_);
441 ClearBit(index, (*item->allocated_resource)->inherit_content_);
442 }
443
444 /*
445 * Store a name string at specified address
446 * A name string is limited to MAX_RES_NAME_LENGTH
447 */
StoreStrname(LEX * lc,ResourceItem * item,int index,int pass)448 void ConfigurationParser::StoreStrname(LEX* lc,
449 ResourceItem* item,
450 int index,
451 int pass)
452 {
453 LexGetToken(lc, BCT_NAME);
454 if (pass == 1) {
455 char** p = GetItemVariablePointer<char**>(*item);
456 if (*p) { free(*p); }
457 *p = strdup(lc->str);
458 }
459 ScanToEol(lc);
460 SetBit(index, (*item->allocated_resource)->item_present_);
461 ClearBit(index, (*item->allocated_resource)->inherit_content_);
462 }
463
464 /*
465 * Store a string at specified address
466 */
StoreStr(LEX * lc,ResourceItem * item,int index,int pass)467 void ConfigurationParser::StoreStr(LEX* lc,
468 ResourceItem* item,
469 int index,
470 int pass)
471 {
472 LexGetToken(lc, BCT_STRING);
473 if (pass == 1) { SetItemVariableFreeMemory<char*>(*item, strdup(lc->str)); }
474 ScanToEol(lc);
475 SetBit(index, (*item->allocated_resource)->item_present_);
476 ClearBit(index, (*item->allocated_resource)->inherit_content_);
477 }
478
479 /*
480 * Store a string at specified address
481 */
StoreStdstr(LEX * lc,ResourceItem * item,int index,int pass)482 void ConfigurationParser::StoreStdstr(LEX* lc,
483 ResourceItem* item,
484 int index,
485 int pass)
486 {
487 LexGetToken(lc, BCT_STRING);
488 if (pass == 1) { SetItemVariable<std::string>(*item, lc->str); }
489 ScanToEol(lc);
490 SetBit(index, (*item->allocated_resource)->item_present_);
491 ClearBit(index, (*item->allocated_resource)->inherit_content_);
492 }
493
494 /*
495 * Store a directory name at specified address. Note, we do
496 * shell expansion except if the string begins with a vertical
497 * bar (i.e. it will likely be passed to the shell later).
498 */
StoreDir(LEX * lc,ResourceItem * item,int index,int pass)499 void ConfigurationParser::StoreDir(LEX* lc,
500 ResourceItem* item,
501 int index,
502 int pass)
503 {
504 LexGetToken(lc, BCT_STRING);
505 if (pass == 1) {
506 char** p = GetItemVariablePointer<char**>(*item);
507 if (*p) { free(*p); }
508 if (lc->str[0] != '|') {
509 DoShellExpansion(lc->str, SizeofPoolMemory(lc->str));
510 }
511 *p = strdup(lc->str);
512 }
513 ScanToEol(lc);
514 SetBit(index, (*item->allocated_resource)->item_present_);
515 ClearBit(index, (*item->allocated_resource)->inherit_content_);
516 }
517
StoreStdstrdir(LEX * lc,ResourceItem * item,int index,int pass)518 void ConfigurationParser::StoreStdstrdir(LEX* lc,
519 ResourceItem* item,
520 int index,
521 int pass)
522 {
523 LexGetToken(lc, BCT_STRING);
524 if (pass == 1) {
525 if (lc->str[0] != '|') {
526 DoShellExpansion(lc->str, SizeofPoolMemory(lc->str));
527 }
528 SetItemVariable<std::string>(*item, lc->str);
529 }
530 ScanToEol(lc);
531 SetBit(index, (*item->allocated_resource)->item_present_);
532 ClearBit(index, (*item->allocated_resource)->inherit_content_);
533 }
534
535 /*
536 * Store a password at specified address in MD5 coding
537 */
StoreMd5Password(LEX * lc,ResourceItem * item,int index,int pass)538 void ConfigurationParser::StoreMd5Password(LEX* lc,
539 ResourceItem* item,
540 int index,
541 int pass)
542 {
543 LexGetToken(lc, BCT_STRING);
544 if (pass == 1) { /* free old item */
545 s_password* pwd = GetItemVariablePointer<s_password*>(*item);
546
547 if (pwd->value) { free(pwd->value); }
548
549 /*
550 * See if we are parsing an MD5 encoded password already.
551 */
552 if (bstrncmp(lc->str, "[md5]", 5)) {
553 if ((item->code & CFG_ITEM_REQUIRED) == CFG_ITEM_REQUIRED) {
554 static const char* empty_password_md5_hash
555 = "d41d8cd98f00b204e9800998ecf8427e";
556 if (strncmp(lc->str + 5, empty_password_md5_hash,
557 strlen(empty_password_md5_hash))
558 == 0) {
559 Emsg1(M_ERROR_TERM, 0, "No Password for Resource \"%s\" given\n",
560 (*item->allocated_resource)->resource_name_);
561 }
562 }
563 pwd->encoding = p_encoding_md5;
564 pwd->value = strdup(lc->str + 5);
565 } else {
566 unsigned int i, j;
567 MD5_CTX md5c;
568 unsigned char digest[CRYPTO_DIGEST_MD5_SIZE];
569 char sig[100];
570
571 if ((item->code & CFG_ITEM_REQUIRED) == CFG_ITEM_REQUIRED) {
572 if (strnlen(lc->str, MAX_NAME_LENGTH) == 0) {
573 Emsg1(M_ERROR_TERM, 0, "No Password for Resource \"%s\" given\n",
574 (*item->allocated_resource)->resource_name_);
575 }
576 }
577
578 MD5_Init(&md5c);
579 MD5_Update(&md5c, (unsigned char*)(lc->str), lc->str_len);
580 MD5_Final(digest, &md5c);
581 for (i = j = 0; i < sizeof(digest); i++) {
582 sprintf(&sig[j], "%02x", digest[i]);
583 j += 2;
584 }
585 pwd->encoding = p_encoding_md5;
586 pwd->value = strdup(sig);
587 }
588 }
589 ScanToEol(lc);
590 SetBit(index, (*item->allocated_resource)->item_present_);
591 ClearBit(index, (*item->allocated_resource)->inherit_content_);
592 }
593
594 /*
595 * Store a password at specified address in MD5 coding
596 */
StoreClearpassword(LEX * lc,ResourceItem * item,int index,int pass)597 void ConfigurationParser::StoreClearpassword(LEX* lc,
598 ResourceItem* item,
599 int index,
600 int pass)
601 {
602 LexGetToken(lc, BCT_STRING);
603 if (pass == 1) {
604 s_password* pwd = GetItemVariablePointer<s_password*>(*item);
605
606
607 if (pwd->value) { free(pwd->value); }
608
609 if ((item->code & CFG_ITEM_REQUIRED) == CFG_ITEM_REQUIRED) {
610 if (strnlen(lc->str, MAX_NAME_LENGTH) == 0) {
611 Emsg1(M_ERROR_TERM, 0, "No Password for Resource \"%s\" given\n",
612 (*item->allocated_resource)->resource_name_);
613 }
614 }
615
616 pwd->encoding = p_encoding_clear;
617 pwd->value = strdup(lc->str);
618 }
619 ScanToEol(lc);
620 SetBit(index, (*item->allocated_resource)->item_present_);
621 ClearBit(index, (*item->allocated_resource)->inherit_content_);
622 }
623
624 /*
625 * Store a resource at specified address.
626 * If we are in pass 2, do a lookup of the
627 * resource.
628 */
StoreRes(LEX * lc,ResourceItem * item,int index,int pass)629 void ConfigurationParser::StoreRes(LEX* lc,
630 ResourceItem* item,
631 int index,
632 int pass)
633 {
634 LexGetToken(lc, BCT_NAME);
635 if (pass == 2) {
636 BareosResource* res = GetResWithName(item->code, lc->str);
637 if (res == NULL) {
638 scan_err3(
639 lc,
640 _("Could not find config resource \"%s\" referenced on line %d: %s"),
641 lc->str, lc->line_no, lc->line);
642 return;
643 }
644 BareosResource** p = GetItemVariablePointer<BareosResource**>(*item);
645 if (*p) {
646 scan_err3(
647 lc,
648 _("Attempt to redefine resource \"%s\" referenced on line %d: %s"),
649 item->name, lc->line_no, lc->line);
650 return;
651 }
652 *p = res;
653 }
654 ScanToEol(lc);
655 SetBit(index, (*item->allocated_resource)->item_present_);
656 ClearBit(index, (*item->allocated_resource)->inherit_content_);
657 }
658
659 /*
660 * Store a resource pointer in an alist. default_value indicates how many
661 * times this routine can be called -- i.e. how many alists there are.
662 *
663 * If we are in pass 2, do a lookup of the resource.
664 */
StoreAlistRes(LEX * lc,ResourceItem * item,int index,int pass)665 void ConfigurationParser::StoreAlistRes(LEX* lc,
666 ResourceItem* item,
667 int index,
668 int pass)
669 {
670 alist** alistvalue = GetItemVariablePointer<alist**>(*item);
671 if (pass == 2) {
672 if (!*alistvalue) { *alistvalue = new alist(10, not_owned_by_alist); }
673 }
674 alist* list = *alistvalue;
675
676 int token = BCT_COMMA;
677 while (token == BCT_COMMA) {
678 LexGetToken(lc, BCT_NAME); /* scan next item */
679 if (pass == 2) {
680 BareosResource* res = GetResWithName(item->code, lc->str);
681 if (res == NULL) {
682 scan_err3(lc,
683 _("Could not find config Resource \"%s\" referenced on line "
684 "%d : %s\n"),
685 item->name, lc->line_no, lc->line);
686 return;
687 }
688 Dmsg5(900, "Append %p (%s) to alist %p size=%d %s\n", res,
689 res->resource_name_, list, list->size(), item->name);
690 list->append(res);
691 }
692 token = LexGetToken(lc, BCT_ALL);
693 }
694 SetBit(index, (*item->allocated_resource)->item_present_);
695 ClearBit(index, (*item->allocated_resource)->inherit_content_);
696 }
697
698 /*
699 * Store a std::string in an std::vector<std::string>.
700 */
StoreStdVectorStr(LEX * lc,ResourceItem * item,int index,int pass)701 void ConfigurationParser::StoreStdVectorStr(LEX* lc,
702 ResourceItem* item,
703 int index,
704 int pass)
705 {
706 std::vector<std::string>* list{nullptr};
707 if (pass == 2) {
708 list = GetItemVariablePointer<std::vector<std::string>*>(*item);
709 }
710 int token = BCT_COMMA;
711 while (token == BCT_COMMA) {
712 LexGetToken(lc, BCT_STRING); /* scan next item */
713 if (pass == 2) {
714 Dmsg4(900, "Append %s to vector %p size=%d %s\n", lc->str, list,
715 list->size(), item->name);
716
717 /*
718 * See if we need to drop the default value.
719 *
720 * We first check to see if the config item has the CFG_ITEM_DEFAULT
721 * flag set and currently has exactly one entry.
722 */
723 if (!BitIsSet(index, (*item->allocated_resource)->item_present_)) {
724 if ((item->flags & CFG_ITEM_DEFAULT) && list->size() == 1) {
725 if (list->at(0) == item->default_value) { list->clear(); }
726 }
727 }
728 list->push_back(lc->str);
729 }
730 token = LexGetToken(lc, BCT_ALL);
731 }
732 SetBit(index, (*item->allocated_resource)->item_present_);
733 ClearBit(index, (*item->allocated_resource)->inherit_content_);
734 }
735
736 /*
737 * Store a string in an alist.
738 */
StoreAlistStr(LEX * lc,ResourceItem * item,int index,int pass)739 void ConfigurationParser::StoreAlistStr(LEX* lc,
740 ResourceItem* item,
741 int index,
742 int pass)
743 {
744 alist** alistvalue = GetItemVariablePointer<alist**>(*item);
745 if (pass == 2) {
746 if (!*alistvalue) { *alistvalue = new alist(10, owned_by_alist); }
747 }
748 alist* list = *alistvalue;
749
750 int token = BCT_COMMA;
751 while (token == BCT_COMMA) {
752 LexGetToken(lc, BCT_STRING); /* scan next item */
753
754 if (pass == 2) {
755 Dmsg4(900, "Append %s to alist %p size=%d %s\n", lc->str, list,
756 list->size(), item->name);
757
758 /*
759 * See if we need to drop the default value from the alist.
760 *
761 * We first check to see if the config item has the CFG_ITEM_DEFAULT
762 * flag set and currently has exactly one entry.
763 */
764 if (!BitIsSet(index, (*item->allocated_resource)->item_present_)) {
765 if ((item->flags & CFG_ITEM_DEFAULT) && list->size() == 1) {
766 char* entry = (char*)list->first();
767 if (bstrcmp(entry, item->default_value)) {
768 list->destroy();
769 list->init(10, owned_by_alist);
770 }
771 }
772 }
773 list->append(strdup(lc->str));
774 }
775 token = LexGetToken(lc, BCT_ALL);
776 }
777 SetBit(index, (*item->allocated_resource)->item_present_);
778 ClearBit(index, (*item->allocated_resource)->inherit_content_);
779 }
780
781 /*
782 * Store a directory name at specified address in an alist.
783 * Note, we do shell expansion except if the string begins
784 * with a vertical bar (i.e. it will likely be passed to the
785 * shell later).
786 */
StoreAlistDir(LEX * lc,ResourceItem * item,int index,int pass)787 void ConfigurationParser::StoreAlistDir(LEX* lc,
788 ResourceItem* item,
789 int index,
790 int pass)
791 {
792 if (pass == 2) {
793 alist** alistvalue = GetItemVariablePointer<alist**>(*item);
794 if (!*alistvalue) { *alistvalue = new alist(10, owned_by_alist); }
795 alist* list = *alistvalue;
796
797 LexGetToken(lc, BCT_STRING); /* scan next item */
798 Dmsg4(900, "Append %s to alist %p size=%d %s\n", lc->str, list,
799 list->size(), item->name);
800
801 if (lc->str[0] != '|') {
802 DoShellExpansion(lc->str, SizeofPoolMemory(lc->str));
803 }
804
805 /*
806 * See if we need to drop the default value from the alist.
807 *
808 * We first check to see if the config item has the CFG_ITEM_DEFAULT
809 * flag set and currently has exactly one entry.
810 */
811 if ((item->flags & CFG_ITEM_DEFAULT) && list->size() == 1) {
812 char* entry;
813
814 entry = (char*)list->first();
815 if (bstrcmp(entry, item->default_value)) {
816 list->destroy();
817 list->init(10, owned_by_alist);
818 }
819 }
820
821 list->append(strdup(lc->str));
822 }
823 ScanToEol(lc);
824 SetBit(index, (*item->allocated_resource)->item_present_);
825 ClearBit(index, (*item->allocated_resource)->inherit_content_);
826 }
827
828 /*
829 * Store a list of plugin names to load by the daemon on startup.
830 */
StorePluginNames(LEX * lc,ResourceItem * item,int index,int pass)831 void ConfigurationParser::StorePluginNames(LEX* lc,
832 ResourceItem* item,
833 int index,
834 int pass)
835 {
836 if (pass == 1) {
837 ScanToEol(lc);
838 return;
839 }
840
841 alist** alistvalue = GetItemVariablePointer<alist**>(*item);
842 if (!*alistvalue) { *alistvalue = new alist(10, owned_by_alist); }
843
844 bool finish = false;
845 while (!finish) {
846 switch (LexGetToken(lc, BCT_ALL)) {
847 case BCT_EOL:
848 finish = true;
849 break;
850 case BCT_COMMA:
851 continue;
852 case BCT_UNQUOTED_STRING:
853 case BCT_QUOTED_STRING: {
854 char* p0 = strdup(lc->str);
855 char* p1 = p0;
856 char* p2 = p0;
857 while (p1) {
858 p2 = strchr(p1, ':'); // split at ':'
859 if (p2 != nullptr) { *p2++ = '\0'; }
860 (*alistvalue)->append(strdup(p1));
861 p1 = p2;
862 }
863 free(p0);
864 break;
865 }
866 default:
867 finish = true;
868 break;
869 }
870 }
871 SetBit(index, (*item->allocated_resource)->item_present_);
872 ClearBit(index, (*item->allocated_resource)->inherit_content_);
873 }
874
875 /*
876 * Store default values for Resource from xxxDefs
877 * If we are in pass 2, do a lookup of the
878 * resource and store everything not explicitly set
879 * in main resource.
880 *
881 * Note, here item points to the main resource (e.g. Job, not
882 * the jobdefs, which we look up).
883 */
StoreDefs(LEX * lc,ResourceItem * item,int index,int pass)884 void ConfigurationParser::StoreDefs(LEX* lc,
885 ResourceItem* item,
886 int index,
887 int pass)
888 {
889 BareosResource* res;
890
891 LexGetToken(lc, BCT_NAME);
892 if (pass == 2) {
893 Dmsg2(900, "Code=%d name=%s\n", item->code, lc->str);
894 res = GetResWithName(item->code, lc->str);
895 if (res == NULL) {
896 scan_err3(
897 lc, _("Missing config Resource \"%s\" referenced on line %d : %s\n"),
898 lc->str, lc->line_no, lc->line);
899 return;
900 }
901 }
902 ScanToEol(lc);
903 }
904
905 /*
906 * Store an integer at specified address
907 */
store_int16(LEX * lc,ResourceItem * item,int index,int pass)908 void ConfigurationParser::store_int16(LEX* lc,
909 ResourceItem* item,
910 int index,
911 int pass)
912 {
913 LexGetToken(lc, BCT_INT16);
914 SetItemVariable<int16_t>(*item, lc->u.int16_val);
915 ScanToEol(lc);
916 SetBit(index, (*item->allocated_resource)->item_present_);
917 ClearBit(index, (*item->allocated_resource)->inherit_content_);
918 }
919
store_int32(LEX * lc,ResourceItem * item,int index,int pass)920 void ConfigurationParser::store_int32(LEX* lc,
921 ResourceItem* item,
922 int index,
923 int pass)
924 {
925 LexGetToken(lc, BCT_INT32);
926 SetItemVariable<int32_t>(*item, lc->u.int32_val);
927 ScanToEol(lc);
928 SetBit(index, (*item->allocated_resource)->item_present_);
929 ClearBit(index, (*item->allocated_resource)->inherit_content_);
930 }
931
932 /*
933 * Store a positive integer at specified address
934 */
store_pint16(LEX * lc,ResourceItem * item,int index,int pass)935 void ConfigurationParser::store_pint16(LEX* lc,
936 ResourceItem* item,
937 int index,
938 int pass)
939 {
940 LexGetToken(lc, BCT_PINT16);
941 SetItemVariable<uint16_t>(*item, lc->u.pint16_val);
942 ScanToEol(lc);
943 SetBit(index, (*item->allocated_resource)->item_present_);
944 ClearBit(index, (*item->allocated_resource)->inherit_content_);
945 }
946
store_pint32(LEX * lc,ResourceItem * item,int index,int pass)947 void ConfigurationParser::store_pint32(LEX* lc,
948 ResourceItem* item,
949 int index,
950 int pass)
951 {
952 LexGetToken(lc, BCT_PINT32);
953 SetItemVariable<uint32_t>(*item, lc->u.pint32_val);
954 ScanToEol(lc);
955 SetBit(index, (*item->allocated_resource)->item_present_);
956 ClearBit(index, (*item->allocated_resource)->inherit_content_);
957 }
958
959 /*
960 * Store an 64 bit integer at specified address
961 */
store_int64(LEX * lc,ResourceItem * item,int index,int pass)962 void ConfigurationParser::store_int64(LEX* lc,
963 ResourceItem* item,
964 int index,
965 int pass)
966 {
967 LexGetToken(lc, BCT_INT64);
968 SetItemVariable<int64_t>(*item, lc->u.int64_val);
969 ScanToEol(lc);
970 SetBit(index, (*item->allocated_resource)->item_present_);
971 ClearBit(index, (*item->allocated_resource)->inherit_content_);
972 }
973
974 /*
975 * Store a size in bytes
976 */
store_int_unit(LEX * lc,ResourceItem * item,int index,int pass,bool size32,enum unit_type type)977 void ConfigurationParser::store_int_unit(LEX* lc,
978 ResourceItem* item,
979 int index,
980 int pass,
981 bool size32,
982 enum unit_type type)
983 {
984 uint64_t uvalue;
985 char bsize[500];
986
987 Dmsg0(900, "Enter store_unit\n");
988 int token = LexGetToken(lc, BCT_SKIP_EOL);
989 errno = 0;
990 switch (token) {
991 case BCT_NUMBER:
992 case BCT_IDENTIFIER:
993 case BCT_UNQUOTED_STRING:
994 bstrncpy(bsize, lc->str, sizeof(bsize)); /* save first part */
995 /*
996 * If terminated by space, scan and get modifier
997 */
998 while (lc->ch == ' ') {
999 token = LexGetToken(lc, BCT_ALL);
1000 switch (token) {
1001 case BCT_NUMBER:
1002 case BCT_IDENTIFIER:
1003 case BCT_UNQUOTED_STRING:
1004 bstrncat(bsize, lc->str, sizeof(bsize));
1005 break;
1006 }
1007 }
1008
1009 switch (type) {
1010 case STORE_SIZE:
1011 if (!size_to_uint64(bsize, &uvalue)) {
1012 scan_err1(lc, _("expected a size number, got: %s"), lc->str);
1013 return;
1014 }
1015 break;
1016 case STORE_SPEED:
1017 if (!speed_to_uint64(bsize, &uvalue)) {
1018 scan_err1(lc, _("expected a speed number, got: %s"), lc->str);
1019 return;
1020 }
1021 break;
1022 default:
1023 scan_err0(lc, _("unknown unit type encountered"));
1024 return;
1025 }
1026
1027 if (size32) {
1028 SetItemVariable<uint32_t>(*item, uvalue);
1029 } else {
1030 switch (type) {
1031 case STORE_SIZE:
1032 SetItemVariable<int64_t>(*item, uvalue);
1033 break;
1034 case STORE_SPEED:
1035 SetItemVariable<uint64_t>(*item, uvalue);
1036 break;
1037 }
1038 }
1039 break;
1040 default:
1041 scan_err2(lc, _("expected a %s, got: %s"),
1042 (type == STORE_SIZE) ? _("size") : _("speed"), lc->str);
1043 return;
1044 }
1045 if (token != BCT_EOL) { ScanToEol(lc); }
1046 SetBit(index, (*item->allocated_resource)->item_present_);
1047 ClearBit(index, (*item->allocated_resource)->inherit_content_);
1048 Dmsg0(900, "Leave store_unit\n");
1049 }
1050
1051 /*
1052 * Store a size in bytes
1053 */
store_size32(LEX * lc,ResourceItem * item,int index,int pass)1054 void ConfigurationParser::store_size32(LEX* lc,
1055 ResourceItem* item,
1056 int index,
1057 int pass)
1058 {
1059 store_int_unit(lc, item, index, pass, true /* 32 bit */, STORE_SIZE);
1060 }
1061
1062 /*
1063 * Store a size in bytes
1064 */
store_size64(LEX * lc,ResourceItem * item,int index,int pass)1065 void ConfigurationParser::store_size64(LEX* lc,
1066 ResourceItem* item,
1067 int index,
1068 int pass)
1069 {
1070 store_int_unit(lc, item, index, pass, false /* not 32 bit */, STORE_SIZE);
1071 }
1072
1073 /*
1074 * Store a speed in bytes/s
1075 */
StoreSpeed(LEX * lc,ResourceItem * item,int index,int pass)1076 void ConfigurationParser::StoreSpeed(LEX* lc,
1077 ResourceItem* item,
1078 int index,
1079 int pass)
1080 {
1081 store_int_unit(lc, item, index, pass, false /* 64 bit */, STORE_SPEED);
1082 }
1083
1084 /*
1085 * Store a time period in seconds
1086 */
StoreTime(LEX * lc,ResourceItem * item,int index,int pass)1087 void ConfigurationParser::StoreTime(LEX* lc,
1088 ResourceItem* item,
1089 int index,
1090 int pass)
1091 {
1092 utime_t utime;
1093 char period[500];
1094
1095 int token = LexGetToken(lc, BCT_SKIP_EOL);
1096 errno = 0;
1097 switch (token) {
1098 case BCT_NUMBER:
1099 case BCT_IDENTIFIER:
1100 case BCT_UNQUOTED_STRING:
1101 bstrncpy(period, lc->str, sizeof(period)); /* get first part */
1102 /*
1103 * If terminated by space, scan and get modifier
1104 */
1105 while (lc->ch == ' ') {
1106 token = LexGetToken(lc, BCT_ALL);
1107 switch (token) {
1108 case BCT_NUMBER:
1109 case BCT_IDENTIFIER:
1110 case BCT_UNQUOTED_STRING:
1111 bstrncat(period, lc->str, sizeof(period));
1112 break;
1113 }
1114 }
1115 if (!DurationToUtime(period, &utime)) {
1116 scan_err1(lc, _("expected a time period, got: %s"), period);
1117 return;
1118 }
1119 SetItemVariable<utime_t>(*item, utime);
1120 break;
1121 default:
1122 scan_err1(lc, _("expected a time period, got: %s"), lc->str);
1123 return;
1124 }
1125 if (token != BCT_EOL) { ScanToEol(lc); }
1126 SetBit(index, (*item->allocated_resource)->item_present_);
1127 ClearBit(index, (*item->allocated_resource)->inherit_content_);
1128 }
1129
1130 /*
1131 * Store a yes/no in a bit field
1132 */
StoreBit(LEX * lc,ResourceItem * item,int index,int pass)1133 void ConfigurationParser::StoreBit(LEX* lc,
1134 ResourceItem* item,
1135 int index,
1136 int pass)
1137 {
1138 LexGetToken(lc, BCT_NAME);
1139 char* bitvalue = GetItemVariablePointer<char*>(*item);
1140 if (Bstrcasecmp(lc->str, "yes") || Bstrcasecmp(lc->str, "true")) {
1141 SetBit(item->code, bitvalue);
1142 } else if (Bstrcasecmp(lc->str, "no") || Bstrcasecmp(lc->str, "false")) {
1143 ClearBit(item->code, bitvalue);
1144 } else {
1145 scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE",
1146 lc->str); /* YES and NO must not be translated */
1147 return;
1148 }
1149 ScanToEol(lc);
1150 SetBit(index, (*item->allocated_resource)->item_present_);
1151 ClearBit(index, (*item->allocated_resource)->inherit_content_);
1152 }
1153
1154 /*
1155 * Store a bool in a bit field
1156 */
StoreBool(LEX * lc,ResourceItem * item,int index,int pass)1157 void ConfigurationParser::StoreBool(LEX* lc,
1158 ResourceItem* item,
1159 int index,
1160 int pass)
1161 {
1162 LexGetToken(lc, BCT_NAME);
1163 if (Bstrcasecmp(lc->str, "yes") || Bstrcasecmp(lc->str, "true")) {
1164 SetItemVariable<bool>(*item, true);
1165 } else if (Bstrcasecmp(lc->str, "no") || Bstrcasecmp(lc->str, "false")) {
1166 SetItemVariable<bool>(*item, false);
1167 } else {
1168 scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE",
1169 lc->str); /* YES and NO must not be translated */
1170 return;
1171 }
1172 ScanToEol(lc);
1173 SetBit(index, (*item->allocated_resource)->item_present_);
1174 ClearBit(index, (*item->allocated_resource)->inherit_content_);
1175 }
1176
1177 /*
1178 * Store Tape Label Type (BAREOS, ANSI, IBM)
1179 */
StoreLabel(LEX * lc,ResourceItem * item,int index,int pass)1180 void ConfigurationParser::StoreLabel(LEX* lc,
1181 ResourceItem* item,
1182 int index,
1183 int pass)
1184 {
1185 LexGetToken(lc, BCT_NAME);
1186 /*
1187 * Store the label pass 2 so that type is defined
1188 */
1189 int i;
1190 for (i = 0; tapelabels[i].name; i++) {
1191 if (Bstrcasecmp(lc->str, tapelabels[i].name)) {
1192 SetItemVariable<uint32_t>(*item, tapelabels[i].token);
1193 i = 0;
1194 break;
1195 }
1196 }
1197 if (i != 0) {
1198 scan_err1(lc, _("Expected a Tape Label keyword, got: %s"), lc->str);
1199 return;
1200 }
1201 ScanToEol(lc);
1202 SetBit(index, (*item->allocated_resource)->item_present_);
1203 ClearBit(index, (*item->allocated_resource)->inherit_content_);
1204 }
1205
1206 /*
1207 * Store network addresses.
1208 *
1209 * my tests
1210 * positiv
1211 * = { ip = { addr = 1.2.3.4; port = 1205; } ipv4 = { addr = 1.2.3.4; port =
1212 * http; } } = { ip = { addr = 1.2.3.4; port = 1205; } ipv4 = { addr = 1.2.3.4;
1213 * port = http; } ipv6 = { addr = 1.2.3.4; port = 1205;
1214 * }
1215 * ip = {
1216 * addr = 1.2.3.4
1217 * port = 1205
1218 * }
1219 * ip = {
1220 * addr = 1.2.3.4
1221 * }
1222 * ip = {
1223 * addr = 2001:220:222::2
1224 * }
1225 * ip = {
1226 * addr = bluedot.thun.net
1227 * }
1228 * }
1229 * negativ
1230 * = { ip = { } }
1231 * = { ipv4 { addr = doof.nowaytoheavenxyz.uhu; } }
1232 * = { ipv4 { port = 4711 } }
1233 */
StoreAddresses(LEX * lc,ResourceItem * item,int index,int pass)1234 void ConfigurationParser::StoreAddresses(LEX* lc,
1235 ResourceItem* item,
1236 int index,
1237 int pass)
1238 {
1239 int token;
1240 int exist;
1241 int family = 0;
1242 char errmsg[1024];
1243 char port_str[128];
1244 char hostname_str[1024];
1245 enum
1246 {
1247 EMPTYLINE = 0x0,
1248 PORTLINE = 0x1,
1249 ADDRLINE = 0x2
1250 } next_line
1251 = EMPTYLINE;
1252 int port = str_to_int32(item->default_value);
1253
1254 token = LexGetToken(lc, BCT_SKIP_EOL);
1255 if (token != BCT_BOB) {
1256 scan_err1(lc, _("Expected a block begin { , got: %s"), lc->str);
1257 }
1258 token = LexGetToken(lc, BCT_SKIP_EOL);
1259 if (token == BCT_EOB) { scan_err0(lc, _("Empty addr block is not allowed")); }
1260 do {
1261 if (!(token == BCT_UNQUOTED_STRING || token == BCT_IDENTIFIER)) {
1262 scan_err1(lc, _("Expected a string, got: %s"), lc->str);
1263 }
1264 if (Bstrcasecmp("ip", lc->str) || Bstrcasecmp("ipv4", lc->str)) {
1265 family = AF_INET;
1266 #ifdef HAVE_IPV6
1267 } else if (Bstrcasecmp("ipv6", lc->str)) {
1268 family = AF_INET6;
1269 } else {
1270 scan_err1(lc, _("Expected a string [ip|ipv4|ipv6], got: %s"), lc->str);
1271 }
1272 #else
1273 } else {
1274 scan_err1(lc, _("Expected a string [ip|ipv4], got: %s"), lc->str);
1275 }
1276 #endif
1277 token = LexGetToken(lc, BCT_SKIP_EOL);
1278 if (token != BCT_EQUALS) {
1279 scan_err1(lc, _("Expected a equal =, got: %s"), lc->str);
1280 }
1281 token = LexGetToken(lc, BCT_SKIP_EOL);
1282 if (token != BCT_BOB) {
1283 scan_err1(lc, _("Expected a block begin { , got: %s"), lc->str);
1284 }
1285 token = LexGetToken(lc, BCT_SKIP_EOL);
1286 exist = EMPTYLINE;
1287 port_str[0] = hostname_str[0] = '\0';
1288 do {
1289 if (token != BCT_IDENTIFIER) {
1290 scan_err1(lc, _("Expected a identifier [addr|port], got: %s"), lc->str);
1291 }
1292 if (Bstrcasecmp("port", lc->str)) {
1293 next_line = PORTLINE;
1294 if (exist & PORTLINE) {
1295 scan_err0(lc, _("Only one port per address block"));
1296 }
1297 exist |= PORTLINE;
1298 } else if (Bstrcasecmp("addr", lc->str)) {
1299 next_line = ADDRLINE;
1300 if (exist & ADDRLINE) {
1301 scan_err0(lc, _("Only one addr per address block"));
1302 }
1303 exist |= ADDRLINE;
1304 } else {
1305 scan_err1(lc, _("Expected a identifier [addr|port], got: %s"), lc->str);
1306 }
1307 token = LexGetToken(lc, BCT_SKIP_EOL);
1308 if (token != BCT_EQUALS) {
1309 scan_err1(lc, _("Expected a equal =, got: %s"), lc->str);
1310 }
1311 token = LexGetToken(lc, BCT_SKIP_EOL);
1312 switch (next_line) {
1313 case PORTLINE:
1314 if (!(token == BCT_UNQUOTED_STRING || token == BCT_NUMBER
1315 || token == BCT_IDENTIFIER)) {
1316 scan_err1(lc, _("Expected a number or a string, got: %s"), lc->str);
1317 }
1318 bstrncpy(port_str, lc->str, sizeof(port_str));
1319 break;
1320 case ADDRLINE:
1321 if (!(token == BCT_UNQUOTED_STRING || token == BCT_IDENTIFIER)) {
1322 scan_err1(lc, _("Expected an IP number or a hostname, got: %s"),
1323 lc->str);
1324 }
1325 bstrncpy(hostname_str, lc->str, sizeof(hostname_str));
1326 break;
1327 case EMPTYLINE:
1328 scan_err0(lc, _("State machine mismatch"));
1329 break;
1330 }
1331 token = LexGetToken(lc, BCT_SKIP_EOL);
1332 } while (token == BCT_IDENTIFIER);
1333 if (token != BCT_EOB) {
1334 scan_err1(lc, _("Expected a end of block }, got: %s"), lc->str);
1335 }
1336 if (pass == 1
1337 && !AddAddress(GetItemVariablePointer<dlist**>(*item),
1338 IPADDR::R_MULTIPLE, htons(port), family, hostname_str,
1339 port_str, errmsg, sizeof(errmsg))) {
1340 scan_err3(lc, _("Can't add hostname(%s) and port(%s) to addrlist (%s)"),
1341 hostname_str, port_str, errmsg);
1342 }
1343 token = ScanToNextNotEol(lc);
1344 } while ((token == BCT_IDENTIFIER || token == BCT_UNQUOTED_STRING));
1345 if (token != BCT_EOB) {
1346 scan_err1(lc, _("Expected a end of block }, got: %s"), lc->str);
1347 }
1348 SetBit(index, (*item->allocated_resource)->item_present_);
1349 ClearBit(index, (*item->allocated_resource)->inherit_content_);
1350 }
1351
StoreAddressesAddress(LEX * lc,ResourceItem * item,int index,int pass)1352 void ConfigurationParser::StoreAddressesAddress(LEX* lc,
1353 ResourceItem* item,
1354 int index,
1355 int pass)
1356 {
1357 int token;
1358 char errmsg[1024];
1359 int port = str_to_int32(item->default_value);
1360
1361 token = LexGetToken(lc, BCT_SKIP_EOL);
1362 if (!(token == BCT_UNQUOTED_STRING || token == BCT_NUMBER
1363 || token == BCT_IDENTIFIER)) {
1364 scan_err1(lc, _("Expected an IP number or a hostname, got: %s"), lc->str);
1365 }
1366 if (pass == 1
1367 && !AddAddress(GetItemVariablePointer<dlist**>(*item),
1368 IPADDR::R_SINGLE_ADDR, htons(port), AF_INET, lc->str, 0,
1369 errmsg, sizeof(errmsg))) {
1370 scan_err2(lc, _("can't add port (%s) to (%s)"), lc->str, errmsg);
1371 }
1372 }
1373
StoreAddressesPort(LEX * lc,ResourceItem * item,int index,int pass)1374 void ConfigurationParser::StoreAddressesPort(LEX* lc,
1375 ResourceItem* item,
1376 int index,
1377 int pass)
1378 {
1379 int token;
1380 char errmsg[1024];
1381 int port = str_to_int32(item->default_value);
1382
1383 token = LexGetToken(lc, BCT_SKIP_EOL);
1384 if (!(token == BCT_UNQUOTED_STRING || token == BCT_NUMBER
1385 || token == BCT_IDENTIFIER)) {
1386 scan_err1(lc, _("Expected a port number or string, got: %s"), lc->str);
1387 }
1388 if (pass == 1
1389 && !AddAddress(GetItemVariablePointer<dlist**>(*item),
1390 IPADDR::R_SINGLE_PORT, htons(port), AF_INET, 0, lc->str,
1391 errmsg, sizeof(errmsg))) {
1392 scan_err2(lc, _("can't add port (%s) to (%s)"), lc->str, errmsg);
1393 }
1394 }
1395
1396 /*
1397 * Generic store resource dispatcher.
1398 */
StoreResource(int type,LEX * lc,ResourceItem * item,int index,int pass)1399 bool ConfigurationParser::StoreResource(int type,
1400 LEX* lc,
1401 ResourceItem* item,
1402 int index,
1403 int pass)
1404 {
1405 switch (type) {
1406 case CFG_TYPE_STR:
1407 StoreStr(lc, item, index, pass);
1408 break;
1409 case CFG_TYPE_DIR:
1410 StoreDir(lc, item, index, pass);
1411 break;
1412 case CFG_TYPE_STDSTR:
1413 StoreStdstr(lc, item, index, pass);
1414 break;
1415 case CFG_TYPE_STDSTRDIR:
1416 StoreStdstrdir(lc, item, index, pass);
1417 break;
1418 case CFG_TYPE_MD5PASSWORD:
1419 StoreMd5Password(lc, item, index, pass);
1420 break;
1421 case CFG_TYPE_CLEARPASSWORD:
1422 StoreClearpassword(lc, item, index, pass);
1423 break;
1424 case CFG_TYPE_NAME:
1425 StoreName(lc, item, index, pass);
1426 break;
1427 case CFG_TYPE_STRNAME:
1428 StoreStrname(lc, item, index, pass);
1429 break;
1430 case CFG_TYPE_RES:
1431 StoreRes(lc, item, index, pass);
1432 break;
1433 case CFG_TYPE_ALIST_RES:
1434 StoreAlistRes(lc, item, index, pass);
1435 break;
1436 case CFG_TYPE_ALIST_STR:
1437 StoreAlistStr(lc, item, index, pass);
1438 break;
1439 case CFG_TYPE_STR_VECTOR:
1440 case CFG_TYPE_STR_VECTOR_OF_DIRS:
1441 StoreStdVectorStr(lc, item, index, pass);
1442 break;
1443 case CFG_TYPE_ALIST_DIR:
1444 StoreAlistDir(lc, item, index, pass);
1445 break;
1446 case CFG_TYPE_INT16:
1447 store_int16(lc, item, index, pass);
1448 break;
1449 case CFG_TYPE_PINT16:
1450 store_pint16(lc, item, index, pass);
1451 break;
1452 case CFG_TYPE_INT32:
1453 store_int32(lc, item, index, pass);
1454 break;
1455 case CFG_TYPE_PINT32:
1456 store_pint32(lc, item, index, pass);
1457 break;
1458 case CFG_TYPE_MSGS:
1459 StoreMsgs(lc, item, index, pass);
1460 break;
1461 case CFG_TYPE_INT64:
1462 store_int64(lc, item, index, pass);
1463 break;
1464 case CFG_TYPE_BIT:
1465 StoreBit(lc, item, index, pass);
1466 break;
1467 case CFG_TYPE_BOOL:
1468 StoreBool(lc, item, index, pass);
1469 break;
1470 case CFG_TYPE_TIME:
1471 StoreTime(lc, item, index, pass);
1472 break;
1473 case CFG_TYPE_SIZE64:
1474 store_size64(lc, item, index, pass);
1475 break;
1476 case CFG_TYPE_SIZE32:
1477 store_size32(lc, item, index, pass);
1478 break;
1479 case CFG_TYPE_SPEED:
1480 StoreSpeed(lc, item, index, pass);
1481 break;
1482 case CFG_TYPE_DEFS:
1483 StoreDefs(lc, item, index, pass);
1484 break;
1485 case CFG_TYPE_LABEL:
1486 StoreLabel(lc, item, index, pass);
1487 break;
1488 case CFG_TYPE_ADDRESSES:
1489 StoreAddresses(lc, item, index, pass);
1490 break;
1491 case CFG_TYPE_ADDRESSES_ADDRESS:
1492 StoreAddressesAddress(lc, item, index, pass);
1493 break;
1494 case CFG_TYPE_ADDRESSES_PORT:
1495 StoreAddressesPort(lc, item, index, pass);
1496 break;
1497 case CFG_TYPE_PLUGIN_NAMES:
1498 StorePluginNames(lc, item, index, pass);
1499 break;
1500 case CFG_TYPE_DIR_OR_CMD:
1501 StoreDir(lc, item, index, pass);
1502 break;
1503 default:
1504 return false;
1505 }
1506
1507 return true;
1508 }
1509
IndentConfigItem(PoolMem & cfg_str,int level,const char * config_item,bool inherited)1510 void IndentConfigItem(PoolMem& cfg_str,
1511 int level,
1512 const char* config_item,
1513 bool inherited)
1514 {
1515 for (int i = 0; i < level; i++) { PmStrcat(cfg_str, DEFAULT_INDENT_STRING); }
1516 if (inherited) {
1517 PmStrcat(cfg_str, "#");
1518 PmStrcat(cfg_str, DEFAULT_INDENT_STRING);
1519 }
1520 PmStrcat(cfg_str, config_item);
1521 }
1522
PrintNumberSiPrefixFormat(ResourceItem * item,uint64_t value_in)1523 std::string PrintNumberSiPrefixFormat(ResourceItem* item, uint64_t value_in)
1524 {
1525 return SizeAsSiPrefixFormat(value_in);
1526 }
1527
Print32BitConfigNumberSiPrefixFormat(ResourceItem * item)1528 std::string Print32BitConfigNumberSiPrefixFormat(ResourceItem* item)
1529 {
1530 uint32_t value_32_bit = GetItemVariable<uint32_t>(*item);
1531 return PrintNumberSiPrefixFormat(item, value_32_bit);
1532 }
1533
Print64BitConfigNumberSiPrefixFormat(ResourceItem * item)1534 std::string Print64BitConfigNumberSiPrefixFormat(ResourceItem* item)
1535 {
1536 uint64_t value_64_bit = GetItemVariable<uint64_t>(*item);
1537 return PrintNumberSiPrefixFormat(item, value_64_bit);
1538 }
1539
PrintConfigTime(ResourceItem * item)1540 std::string PrintConfigTime(ResourceItem* item)
1541 {
1542 PoolMem temp;
1543 PoolMem timespec;
1544 utime_t secs = GetItemVariable<utime_t>(*item);
1545 int factor;
1546
1547 /*
1548 * Reverse time formatting: 1 Month, 1 Week, etc.
1549 *
1550 * convert default value string to numeric value
1551 */
1552 static const char* modifier[] = {"years", "months", "weeks", "days",
1553 "hours", "minutes", "seconds", NULL};
1554 static const int32_t multiplier[] = {60 * 60 * 24 * 365,
1555 60 * 60 * 24 * 30,
1556 60 * 60 * 24 * 7,
1557 60 * 60 * 24,
1558 60 * 60,
1559 60,
1560 1,
1561 0};
1562
1563 if (secs == 0) {
1564 PmStrcat(timespec, "0");
1565 } else {
1566 for (int t = 0; modifier[t]; t++) {
1567 factor = secs / multiplier[t];
1568 secs = secs % multiplier[t];
1569 if (factor > 0) {
1570 Mmsg(temp, "%d %s ", factor, modifier[t]);
1571 PmStrcat(timespec, temp.c_str());
1572 }
1573 if (secs == 0) { break; }
1574 }
1575 }
1576
1577 return std::string(timespec.c_str());
1578 }
1579
1580 // message destinations
1581 struct s_mdestination {
1582 const char* destination;
1583 bool where;
1584 };
1585
1586 static std::map<MessageDestinationCode, s_mdestination> msg_destinations
1587 = {{MessageDestinationCode::kSyslog, {"syslog", false}},
1588 {MessageDestinationCode::kMail, {"mail", true}},
1589 {MessageDestinationCode::kFile, {"file", true}},
1590 {MessageDestinationCode::kAppend, {"append", true}},
1591 {MessageDestinationCode::kStdout, {"stdout", false}},
1592 {MessageDestinationCode::kStderr, {"stderr", false}},
1593 {MessageDestinationCode::kDirector, {"director", true}},
1594 {MessageDestinationCode::kOperator, {"operator", true}},
1595 {MessageDestinationCode::kConsole, {"console", false}},
1596 {MessageDestinationCode::KMailOnError, {"mailonerror", true}},
1597 {MessageDestinationCode::kMailOnSuccess, {"mailonsuccess", true}},
1598 {MessageDestinationCode::kCatalog, {"catalog", false}}};
1599
1600
GetMessageTypesAsSring(MessageDestinationInfo * d,bool verbose)1601 std::string MessagesResource::GetMessageTypesAsSring(MessageDestinationInfo* d,
1602 bool verbose)
1603 {
1604 std::string cfg_str; /* configuration as string */
1605 PoolMem temp;
1606
1607 int nr_set = 0;
1608 int nr_unset = 0;
1609 PoolMem t; /* set types */
1610 PoolMem u; /* unset types */
1611
1612 for (int j = 0; j < M_MAX - 1; j++) {
1613 if (BitIsSet(msg_types[j].token, d->msg_types_)) {
1614 nr_set++;
1615 Mmsg(temp, ",%s", msg_types[j].name);
1616 PmStrcat(t, temp.c_str());
1617 } else {
1618 Mmsg(temp, ",!%s", msg_types[j].name);
1619 nr_unset++;
1620 PmStrcat(u, temp.c_str());
1621 }
1622 }
1623
1624 if (verbose) {
1625 /* show all message types */
1626 cfg_str += t.c_str() + 1; /* skip first comma */
1627 cfg_str += u.c_str();
1628 } else {
1629 if (nr_set > nr_unset) { /* if more is set than is unset */
1630 cfg_str += "all"; /* all, but not ... */
1631 cfg_str += u.c_str();
1632 } else { /* only print set types */
1633 cfg_str += t.c_str() + 1; /* skip first comma */
1634 }
1635 }
1636
1637 return cfg_str.c_str();
1638 }
1639
PrintConfig(OutputFormatterResource & send,const ConfigurationParser &,bool hide_sensitive_data,bool verbose)1640 bool MessagesResource::PrintConfig(OutputFormatterResource& send,
1641 const ConfigurationParser& /* unused */,
1642 bool hide_sensitive_data,
1643 bool verbose)
1644 {
1645 PoolMem cfg_str; /* configuration as string */
1646 PoolMem temp;
1647 MessagesResource* msgres;
1648 OutputFormatter* of = send.GetOutputFormatter();
1649
1650 msgres = this;
1651
1652 send.ResourceStart("Messages", "Messages", resource_name_);
1653
1654 send.KeyQuotedString("Name", resource_name_);
1655
1656 if (!msgres->mail_cmd_.empty()) {
1657 PoolMem esc;
1658
1659 EscapeString(esc, msgres->mail_cmd_.c_str(), msgres->mail_cmd_.size());
1660 send.KeyQuotedString("MailCommand", esc.c_str());
1661 }
1662
1663 if (!msgres->operator_cmd_.empty()) {
1664 PoolMem esc;
1665
1666 EscapeString(esc, msgres->operator_cmd_.c_str(),
1667 msgres->operator_cmd_.size());
1668 send.KeyQuotedString("OperatorCommand", esc.c_str());
1669 }
1670
1671 if (!msgres->timestamp_format_.empty()) {
1672 PoolMem esc;
1673
1674 EscapeString(esc, msgres->timestamp_format_.c_str(),
1675 msgres->timestamp_format_.size());
1676 send.KeyQuotedString("TimestampFormat", esc.c_str());
1677 }
1678
1679 for (MessageDestinationInfo* d : msgres->dest_chain_) {
1680 auto msg_dest_iter = msg_destinations.find(d->dest_code_);
1681
1682 if (msg_dest_iter != msg_destinations.end()) {
1683 of->ObjectStart(msg_dest_iter->second.destination,
1684 send.GetKeyFormatString(false, "%s").c_str());
1685
1686 if (msg_dest_iter->second.where) {
1687 of->ObjectKeyValue("where", d->where_.c_str(), " = %s");
1688 }
1689 of->ObjectKeyValue("what", GetMessageTypesAsSring(d, verbose).c_str(),
1690 " = %s");
1691 of->ObjectEnd(msg_dest_iter->second.destination, "\n");
1692 }
1693 }
1694
1695 send.ResourceEnd("Messages", "Messages", resource_name_);
1696
1697 return true;
1698 }
1699
GetName(ResourceItem & item,s_kw * keywords)1700 const char* GetName(ResourceItem& item, s_kw* keywords)
1701 {
1702 uint32_t value = GetItemVariable<uint32_t>(item);
1703 for (int j = 0; keywords[j].name; j++) {
1704 if (keywords[j].token == value) { return keywords[j].name; }
1705 }
1706 return nullptr;
1707 }
1708
1709
HasDefaultValue(ResourceItem & item,s_kw * keywords)1710 bool HasDefaultValue(ResourceItem& item, s_kw* keywords)
1711 {
1712 bool is_default = false;
1713 const char* name = GetName(item, keywords);
1714 if (item.flags & CFG_ITEM_DEFAULT) {
1715 is_default = Bstrcasecmp(name, item.default_value);
1716 } else {
1717 if (name == nullptr) { is_default = true; }
1718 }
1719 return is_default;
1720 }
1721
HasDefaultValue(ResourceItem & item)1722 static bool HasDefaultValue(ResourceItem& item)
1723 {
1724 bool is_default = false;
1725
1726 if (item.flags & CFG_ITEM_DEFAULT) {
1727 /*
1728 * Check for default values.
1729 */
1730 switch (item.type) {
1731 case CFG_TYPE_STR:
1732 case CFG_TYPE_DIR:
1733 case CFG_TYPE_DIR_OR_CMD:
1734 case CFG_TYPE_NAME:
1735 case CFG_TYPE_STRNAME:
1736 is_default = bstrcmp(GetItemVariable<char*>(item), item.default_value);
1737 break;
1738 case CFG_TYPE_STDSTR:
1739 case CFG_TYPE_STDSTRDIR:
1740 is_default = bstrcmp(GetItemVariable<std::string&>(item).c_str(),
1741 item.default_value);
1742 break;
1743 case CFG_TYPE_LABEL:
1744 is_default = HasDefaultValue(item, tapelabels);
1745 break;
1746 case CFG_TYPE_INT16:
1747 is_default = (GetItemVariable<int16_t>(item)
1748 == (int16_t)str_to_int32(item.default_value));
1749 break;
1750 case CFG_TYPE_PINT16:
1751 is_default = (GetItemVariable<uint16_t>(item)
1752 == (uint16_t)str_to_int32(item.default_value));
1753 break;
1754 case CFG_TYPE_INT32:
1755 is_default = (GetItemVariable<int32_t>(item)
1756 == str_to_int32(item.default_value));
1757 break;
1758 case CFG_TYPE_PINT32:
1759 is_default = (GetItemVariable<uint32_t>(item)
1760 == (uint32_t)str_to_int32(item.default_value));
1761 break;
1762 case CFG_TYPE_INT64:
1763 is_default = (GetItemVariable<int64_t>(item)
1764 == str_to_int64(item.default_value));
1765 break;
1766 case CFG_TYPE_SPEED:
1767 is_default = (GetItemVariable<uint64_t>(item)
1768 == (uint64_t)str_to_int64(item.default_value));
1769 break;
1770 case CFG_TYPE_SIZE64:
1771 is_default = (GetItemVariable<uint64_t>(item)
1772 == (uint64_t)str_to_int64(item.default_value));
1773 break;
1774 case CFG_TYPE_SIZE32:
1775 is_default = (GetItemVariable<uint32_t>(item)
1776 == (uint32_t)str_to_int32(item.default_value));
1777 break;
1778 case CFG_TYPE_TIME:
1779 is_default = (GetItemVariable<uint64_t>(item)
1780 == (uint64_t)str_to_int64(item.default_value));
1781 break;
1782 case CFG_TYPE_BOOL: {
1783 bool default_value = Bstrcasecmp(item.default_value, "true")
1784 || Bstrcasecmp(item.default_value, "yes");
1785
1786 is_default = (GetItemVariable<bool>(item) == default_value);
1787 break;
1788 }
1789 default:
1790 break;
1791 }
1792 } else {
1793 switch (item.type) {
1794 case CFG_TYPE_STR:
1795 case CFG_TYPE_DIR:
1796 case CFG_TYPE_DIR_OR_CMD:
1797 case CFG_TYPE_NAME:
1798 case CFG_TYPE_STRNAME:
1799 is_default = (GetItemVariable<char*>(item) == nullptr);
1800 break;
1801 case CFG_TYPE_STDSTR:
1802 case CFG_TYPE_STDSTRDIR:
1803 is_default = GetItemVariable<std::string&>(item).empty();
1804 break;
1805 case CFG_TYPE_LABEL:
1806 is_default = HasDefaultValue(item, tapelabels);
1807 break;
1808 case CFG_TYPE_INT16:
1809 is_default = (GetItemVariable<int16_t>(item) == 0);
1810 break;
1811 case CFG_TYPE_PINT16:
1812 is_default = (GetItemVariable<uint16_t>(item) == 0);
1813 break;
1814 case CFG_TYPE_INT32:
1815 is_default = (GetItemVariable<int32_t>(item) == 0);
1816 break;
1817 case CFG_TYPE_PINT32:
1818 is_default = (GetItemVariable<uint32_t>(item) == 0);
1819 break;
1820 case CFG_TYPE_INT64:
1821 is_default = (GetItemVariable<int64_t>(item) == 0);
1822 break;
1823 case CFG_TYPE_SPEED:
1824 is_default = (GetItemVariable<uint64_t>(item) == 0);
1825 break;
1826 case CFG_TYPE_SIZE64:
1827 is_default = (GetItemVariable<uint64_t>(item) == 0);
1828 break;
1829 case CFG_TYPE_SIZE32:
1830 is_default = (GetItemVariable<uint32_t>(item) == 0);
1831 break;
1832 case CFG_TYPE_TIME:
1833 is_default = (GetItemVariable<uint64_t>(item) == 0);
1834 break;
1835 case CFG_TYPE_BOOL:
1836 is_default = (GetItemVariable<bool>(item) == false);
1837 break;
1838 default:
1839 break;
1840 }
1841 }
1842
1843 return is_default;
1844 }
1845
1846
PrintResourceItem(ResourceItem & item,const ConfigurationParser & my_config,OutputFormatterResource & send,bool hide_sensitive_data,bool inherited,bool verbose)1847 void BareosResource::PrintResourceItem(ResourceItem& item,
1848 const ConfigurationParser& my_config,
1849 OutputFormatterResource& send,
1850 bool hide_sensitive_data,
1851 bool inherited,
1852 bool verbose)
1853 {
1854 PoolMem value;
1855 PoolMem temp;
1856 bool print_item = false;
1857
1858 Dmsg3(200, "%s (inherited: %d, verbose: %d):\n", item.name, inherited,
1859 verbose);
1860
1861 /*
1862 * If this is an alias for another config keyword suppress it.
1863 */
1864 if (item.flags & CFG_ITEM_ALIAS) { return; }
1865
1866 if (inherited && (!verbose)) {
1867 /*
1868 * If not in verbose mode, skip inherited directives.
1869 */
1870 return;
1871 }
1872
1873 if ((item.flags & CFG_ITEM_REQUIRED) || !my_config.omit_defaults_) {
1874 /*
1875 * Always print required items or if my_config.omit_defaults_ is false
1876 */
1877 print_item = true;
1878 }
1879
1880 if (HasDefaultValue(item)) {
1881 Dmsg1(200, "%s: default value\n", item.name);
1882
1883 if ((verbose) && (!(item.flags & CFG_ITEM_DEPRECATED))) {
1884 /*
1885 * If value has a expliciet default value and verbose mode is on,
1886 * display directive as inherited.
1887 */
1888 print_item = true;
1889 inherited = true;
1890 }
1891 } else {
1892 print_item = true;
1893 }
1894
1895 if (!print_item) {
1896 Dmsg1(200, "%s: not shown\n", item.name);
1897 return;
1898 }
1899
1900 switch (item.type) {
1901 case CFG_TYPE_STR:
1902 case CFG_TYPE_DIR:
1903 case CFG_TYPE_NAME:
1904 case CFG_TYPE_STRNAME: {
1905 char* p = GetItemVariable<char*>(item);
1906 send.KeyQuotedString(item.name, p, inherited);
1907 break;
1908 }
1909 case CFG_TYPE_DIR_OR_CMD: {
1910 char* p = GetItemVariable<char*>(item);
1911 if (p == nullptr) {
1912 send.KeyQuotedString(item.name, nullptr, inherited);
1913 } else {
1914 EscapeString(temp, p, strlen(p));
1915 send.KeyQuotedString(item.name, temp.c_str(), inherited);
1916 }
1917 break;
1918 }
1919 case CFG_TYPE_STDSTR:
1920 case CFG_TYPE_STDSTRDIR: {
1921 const std::string& p = GetItemVariable<std::string&>(item);
1922 send.KeyQuotedString(item.name, p, inherited);
1923 break;
1924 }
1925 case CFG_TYPE_MD5PASSWORD:
1926 case CFG_TYPE_CLEARPASSWORD:
1927 case CFG_TYPE_AUTOPASSWORD: {
1928 s_password* password = GetItemVariablePointer<s_password*>(item);
1929
1930 if (password && password->value != NULL) {
1931 if (hide_sensitive_data) {
1932 Mmsg(value, "****************");
1933 } else {
1934 switch (password->encoding) {
1935 case p_encoding_clear:
1936 Dmsg2(200, "%s = \"%s\"\n", item.name, password->value);
1937 Mmsg(value, "%s", password->value);
1938 break;
1939 case p_encoding_md5:
1940 Dmsg2(200, "%s = \"[md5]%s\"\n", item.name, password->value);
1941 Mmsg(value, "[md5]%s", password->value);
1942 break;
1943 default:
1944 break;
1945 }
1946 }
1947 send.KeyQuotedString(item.name, value.c_str(), inherited);
1948 }
1949 break;
1950 }
1951 case CFG_TYPE_LABEL:
1952 send.KeyQuotedString(item.name, GetName(item, tapelabels), inherited);
1953 break;
1954 case CFG_TYPE_INT16:
1955 send.KeySignedInt(item.name, GetItemVariable<int16_t>(item), inherited);
1956 break;
1957 case CFG_TYPE_PINT16:
1958 send.KeyUnsignedInt(item.name, GetItemVariable<uint16_t>(item),
1959 inherited);
1960 break;
1961 case CFG_TYPE_INT32:
1962 send.KeySignedInt(item.name, GetItemVariable<int32_t>(item), inherited);
1963 break;
1964 case CFG_TYPE_PINT32:
1965 send.KeyUnsignedInt(item.name, GetItemVariable<uint32_t>(item),
1966 inherited);
1967 break;
1968 case CFG_TYPE_INT64:
1969 send.KeySignedInt(item.name, GetItemVariable<int64_t>(item), inherited);
1970 break;
1971 case CFG_TYPE_SPEED:
1972 send.KeyUnsignedInt(item.name, GetItemVariable<uint64_t>(item),
1973 inherited);
1974 break;
1975 case CFG_TYPE_SIZE64: {
1976 const std::string& value = Print64BitConfigNumberSiPrefixFormat(&item);
1977 send.KeyString(item.name, value, inherited);
1978 break;
1979 }
1980 case CFG_TYPE_SIZE32: {
1981 const std::string& value = Print32BitConfigNumberSiPrefixFormat(&item);
1982 send.KeyString(item.name, value, inherited);
1983 break;
1984 }
1985 case CFG_TYPE_TIME: {
1986 const std::string& value = PrintConfigTime(&item);
1987 send.KeyString(item.name, value, inherited);
1988 break;
1989 }
1990 case CFG_TYPE_BOOL: {
1991 send.KeyBool(item.name, GetItemVariable<bool>(item), inherited);
1992 break;
1993 }
1994 case CFG_TYPE_STR_VECTOR:
1995 case CFG_TYPE_STR_VECTOR_OF_DIRS: {
1996 /*
1997 * One line for each member of the list
1998 */
1999 const std::vector<std::string>& list
2000 = GetItemVariable<std::vector<std::string>&>(item);
2001 send.KeyMultipleStringsOnePerLine(item.name, list, inherited);
2002 break;
2003 }
2004 case CFG_TYPE_ALIST_STR:
2005 case CFG_TYPE_ALIST_DIR:
2006 case CFG_TYPE_PLUGIN_NAMES: {
2007 /*
2008 * One line for each member of the list
2009 */
2010 send.KeyMultipleStringsOnePerLine(
2011 item.name, GetItemVariable<alist*>(item), inherited);
2012 break;
2013 }
2014 case CFG_TYPE_ALIST_RES: {
2015 /*
2016 * Each member of the list is comma-separated
2017 */
2018 send.KeyMultipleStringsOnePerLine(
2019 item.name, GetItemVariable<alist*>(item), GetResourceName, inherited,
2020 true, false);
2021 break;
2022 }
2023 case CFG_TYPE_RES: {
2024 BareosResource* res;
2025
2026 res = GetItemVariable<BareosResource*>(item);
2027 if (res != NULL && res->resource_name_ != NULL) {
2028 send.KeyQuotedString(item.name, res->resource_name_, inherited);
2029 } else {
2030 send.KeyQuotedString(item.name, "", inherited);
2031 }
2032 break;
2033 }
2034 case CFG_TYPE_BIT: {
2035 send.KeyBool(item.name,
2036 BitIsSet(item.code, GetItemVariablePointer<char*>(item)),
2037 inherited);
2038 break;
2039 }
2040 case CFG_TYPE_MSGS:
2041 /*
2042 * We ignore these items as they are printed in a special way in
2043 * MessagesResource::PrintConfig()
2044 */
2045 break;
2046 case CFG_TYPE_ADDRESSES: {
2047 dlist* addrs = GetItemVariable<dlist*>(item);
2048 IPADDR* adr;
2049 send.ArrayStart(item.name, inherited, "%s = {\n");
2050 foreach_dlist (adr, addrs) {
2051 send.SubResourceStart(NULL, inherited, "");
2052 adr->BuildConfigString(send, inherited);
2053 send.SubResourceEnd(NULL, inherited, "");
2054 }
2055 send.ArrayEnd(item.name, inherited, "}\n");
2056 break;
2057 }
2058 case CFG_TYPE_ADDRESSES_PORT:
2059 /*
2060 * Is stored in CFG_TYPE_ADDRESSES and printed there.
2061 */
2062 break;
2063 case CFG_TYPE_ADDRESSES_ADDRESS:
2064 /*
2065 * Is stored in CFG_TYPE_ADDRESSES and printed there.
2066 */
2067 break;
2068 default:
2069 /*
2070 * This is a non-generic type call back to the daemon to get things
2071 * printed.
2072 */
2073 if (my_config.print_res_) {
2074 my_config.print_res_(item, send, hide_sensitive_data, inherited,
2075 verbose);
2076 }
2077 break;
2078 }
2079 }
2080
2081
PrintConfig(OutputFormatterResource & send,const ConfigurationParser & my_config,bool hide_sensitive_data,bool verbose)2082 bool BareosResource::PrintConfig(OutputFormatterResource& send,
2083 const ConfigurationParser& my_config,
2084 bool hide_sensitive_data,
2085 bool verbose)
2086 {
2087 ResourceItem* items;
2088 int rindex;
2089
2090 /*
2091 * If entry is not used, then there is nothing to print.
2092 */
2093 if (rcode_ < (uint32_t)my_config.r_first_ || refcnt_ <= 0) { return true; }
2094
2095 rindex = rcode_ - my_config.r_first_;
2096
2097 /*
2098 * don't dump internal resources.
2099 */
2100 if ((internal_) && (!verbose)) { return true; }
2101 /*
2102 * Make sure the resource class has any items.
2103 */
2104 if (!my_config.resources_[rindex].items) { return true; }
2105 items = my_config.resources_[rindex].items;
2106
2107 *my_config.resources_[rindex].allocated_resource_ = this;
2108
2109 send.ResourceStart(my_config.ResGroupToStr(rcode_),
2110 my_config.ResToStr(rcode_), resource_name_, internal_);
2111
2112 for (int i = 0; items[i].name; i++) {
2113 bool inherited = BitIsSet(i, inherit_content_);
2114 if (internal_) { inherited = true; }
2115 PrintResourceItem(items[i], my_config, send, hide_sensitive_data, inherited,
2116 verbose);
2117 }
2118
2119 send.ResourceEnd(my_config.ResGroupToStr(rcode_), my_config.ResToStr(rcode_),
2120 resource_name_, internal_);
2121
2122 return true;
2123 }
2124
2125
2126 #ifdef HAVE_JANSSON
2127 /*
2128 * resource item schema description in JSON format.
2129 * Example output:
2130 *
2131 * "filesetacl": {
2132 * "datatype": "BOOLEAN",
2133 * "datatype_number": 51,
2134 * "code": int
2135 * [ "defaultvalue": "xyz", ]
2136 * [ "required": true, ]
2137 * [ "alias": true, ]
2138 * [ "deprecated": true, ]
2139 * [ "equals": true, ]
2140 * ...
2141 * "type": "ResourceItem"
2142 * }
2143 */
json_item(ResourceItem * item)2144 json_t* json_item(ResourceItem* item)
2145 {
2146 json_t* json = json_object();
2147
2148 json_object_set_new(json, "datatype",
2149 json_string(DatatypeToString(item->type)));
2150 json_object_set_new(json, "code", json_integer(item->code));
2151
2152 if (item->flags & CFG_ITEM_ALIAS) {
2153 json_object_set_new(json, "alias", json_true());
2154 }
2155 if (item->flags & CFG_ITEM_DEFAULT) {
2156 /* FIXME? would it be better to convert it to the right type before
2157 * returning? */
2158 json_object_set_new(json, "default_value",
2159 json_string(item->default_value));
2160 }
2161 if (item->flags & CFG_ITEM_PLATFORM_SPECIFIC) {
2162 json_object_set_new(json, "platform_specific", json_true());
2163 }
2164 if (item->flags & CFG_ITEM_DEPRECATED) {
2165 json_object_set_new(json, "deprecated", json_true());
2166 }
2167 if (item->flags & CFG_ITEM_NO_EQUALS) {
2168 json_object_set_new(json, "equals", json_false());
2169 } else {
2170 json_object_set_new(json, "equals", json_true());
2171 }
2172 if (item->flags & CFG_ITEM_REQUIRED) {
2173 json_object_set_new(json, "required", json_true());
2174 }
2175 if (item->versions) {
2176 json_object_set_new(json, "versions", json_string(item->versions));
2177 }
2178 if (item->description) {
2179 json_object_set_new(json, "description", json_string(item->description));
2180 }
2181
2182 return json;
2183 }
2184
json_item(s_kw * item)2185 json_t* json_item(s_kw* item)
2186 {
2187 json_t* json = json_object();
2188
2189 json_object_set_new(json, "token", json_integer(item->token));
2190
2191 return json;
2192 }
2193
json_items(ResourceItem items[])2194 json_t* json_items(ResourceItem items[])
2195 {
2196 json_t* json = json_object();
2197
2198 if (items) {
2199 for (int i = 0; items[i].name; i++) {
2200 json_object_set_new(json, items[i].name, json_item(&items[i]));
2201 }
2202 }
2203
2204 return json;
2205 }
2206 #endif
2207
2208 static DatatypeName datatype_names[] = {
2209 /*
2210 * Standard resource types. handlers in res.c
2211 */
2212 {CFG_TYPE_STR, "STRING", "String"},
2213 {CFG_TYPE_DIR, "DIRECTORY", "directory"},
2214 {CFG_TYPE_STDSTR, "STRING", "String"},
2215 {CFG_TYPE_STDSTRDIR, "DIRECTORY", "directory"},
2216 {CFG_TYPE_MD5PASSWORD, "MD5PASSWORD", "Password in MD5 format"},
2217 {CFG_TYPE_CLEARPASSWORD, "CLEARPASSWORD", "Password as cleartext"},
2218 {CFG_TYPE_AUTOPASSWORD, "AUTOPASSWORD",
2219 "Password stored in clear when needed otherwise hashed"},
2220 {CFG_TYPE_NAME, "NAME", "Name"},
2221 {CFG_TYPE_STRNAME, "STRNAME", "String name"},
2222 {CFG_TYPE_RES, "RES", "Resource"},
2223 {CFG_TYPE_ALIST_RES, "RESOURCE_LIST", "Resource list"},
2224 {CFG_TYPE_ALIST_STR, "STRING_LIST", "string list"},
2225 {CFG_TYPE_ALIST_DIR, "DIRECTORY_LIST", "directory list"},
2226 {CFG_TYPE_INT16, "INT16", "Integer 16 bits"},
2227 {CFG_TYPE_PINT16, "PINT16", "Positive 16 bits Integer (unsigned)"},
2228 {CFG_TYPE_INT32, "INT32", "Integer 32 bits"},
2229 {CFG_TYPE_PINT32, "PINT32", "Positive 32 bits Integer (unsigned)"},
2230 {CFG_TYPE_MSGS, "MESSAGES", "Message resource"},
2231 {CFG_TYPE_INT64, "INT64", "Integer 64 bits"},
2232 {CFG_TYPE_BIT, "BIT", "Bitfield"},
2233 {CFG_TYPE_BOOL, "BOOLEAN", "boolean"},
2234 {CFG_TYPE_TIME, "TIME", "time"},
2235 {CFG_TYPE_SIZE64, "SIZE64", "64 bits file size"},
2236 {CFG_TYPE_SIZE32, "SIZE32", "32 bits file size"},
2237 {CFG_TYPE_SPEED, "SPEED", "speed"},
2238 {CFG_TYPE_DEFS, "DEFS", "definition"},
2239 {CFG_TYPE_LABEL, "LABEL", "label"},
2240 {CFG_TYPE_ADDRESSES, "ADDRESSES", "ip addresses list"},
2241 {CFG_TYPE_ADDRESSES_ADDRESS, "ADDRESS", "ip address"},
2242 {CFG_TYPE_ADDRESSES_PORT, "PORT", "network port"},
2243 {CFG_TYPE_PLUGIN_NAMES, "PLUGIN_NAMES", "Plugin Name(s)"},
2244 {CFG_TYPE_STR_VECTOR, "STRING_LIST", "string list"},
2245 {CFG_TYPE_STR_VECTOR_OF_DIRS, "DIRECTORY_LIST", "directory list"},
2246 {CFG_TYPE_DIR_OR_CMD, "DIRECTORY_OR_COMMAND", "Directory or command"},
2247
2248 /*
2249 * Director resource types. handlers in dird_conf.
2250 */
2251 {CFG_TYPE_ACL, "ACL", "User Access Control List"},
2252 {CFG_TYPE_AUDIT, "AUDIT_COMMAND_LIST", "Auditing Command List"},
2253 {CFG_TYPE_AUTHPROTOCOLTYPE, "AUTH_PROTOCOL_TYPE",
2254 "Authentication Protocol"},
2255 {CFG_TYPE_AUTHTYPE, "AUTH_TYPE", "Authentication Type"},
2256 {CFG_TYPE_DEVICE, "DEVICE", "Device resource"},
2257 {CFG_TYPE_JOBTYPE, "JOB_TYPE", "Type of Job"},
2258 {CFG_TYPE_PROTOCOLTYPE, "PROTOCOL_TYPE", "Protocol"},
2259 {CFG_TYPE_LEVEL, "BACKUP_LEVEL", "Backup Level"},
2260 {CFG_TYPE_REPLACE, "REPLACE_OPTION", "Replace option"},
2261 {CFG_TYPE_SHRTRUNSCRIPT, "RUNSCRIPT_SHORT", "Short Runscript definition"},
2262 {CFG_TYPE_RUNSCRIPT, "RUNSCRIPT", "Runscript"},
2263 {CFG_TYPE_RUNSCRIPT_CMD, "RUNSCRIPT_COMMAND", "Runscript Command"},
2264 {CFG_TYPE_RUNSCRIPT_TARGET, "RUNSCRIPT_TARGET", "Runscript Target (Host)"},
2265 {CFG_TYPE_RUNSCRIPT_BOOL, "RUNSCRIPT_BOOLEAN", "Runscript Boolean"},
2266 {CFG_TYPE_RUNSCRIPT_WHEN, "RUNSCRIPT_WHEN", "Runscript When expression"},
2267 {CFG_TYPE_MIGTYPE, "MIGRATION_TYPE", "Migration Type"},
2268 {CFG_TYPE_INCEXC, "INCLUDE_EXCLUDE_ITEM", "Include/Exclude item"},
2269 {CFG_TYPE_RUN, "SCHEDULE_RUN_COMMAND", "Schedule Run Command"},
2270 {CFG_TYPE_ACTIONONPURGE, "ACTION_ON_PURGE", "Action to perform on Purge"},
2271 {CFG_TYPE_POOLTYPE, "POOLTYPE", "Pool Type"},
2272
2273 /*
2274 * Director fileset options. handlers in dird_conf.
2275 */
2276 {CFG_TYPE_FNAME, "FILENAME", "Filename"},
2277 {CFG_TYPE_PLUGINNAME, "PLUGIN_NAME", "Pluginname"},
2278 {CFG_TYPE_EXCLUDEDIR, "EXCLUDE_DIRECTORY", "Exclude directory"},
2279 {CFG_TYPE_OPTIONS, "OPTIONS", "Options block"},
2280 {CFG_TYPE_OPTION, "OPTION", "Option of Options block"},
2281 {CFG_TYPE_REGEX, "REGEX", "Regular Expression"},
2282 {CFG_TYPE_BASE, "BASEJOB", "Basejob Expression"},
2283 {CFG_TYPE_WILD, "WILDCARD", "Wildcard Expression"},
2284 {CFG_TYPE_PLUGIN, "PLUGIN", "Plugin definition"},
2285 {CFG_TYPE_FSTYPE, "FILESYSTEM_TYPE", "FileSystem match criterium (UNIX)"},
2286 {CFG_TYPE_DRIVETYPE, "DRIVE_TYPE", "DriveType match criterium (Windows)"},
2287 {CFG_TYPE_META, "META_TAG", "Meta tag"},
2288
2289 /*
2290 * Storage daemon resource types
2291 */
2292 {CFG_TYPE_DEVTYPE, "DEVICE_TYPE", "Device Type"},
2293 {CFG_TYPE_MAXBLOCKSIZE, "MAX_BLOCKSIZE", "Maximum Blocksize"},
2294 {CFG_TYPE_IODIRECTION, "IO_DIRECTION", "IO Direction"},
2295 {CFG_TYPE_CMPRSALGO, "COMPRESSION_ALGORITHM", "Compression Algorithm"},
2296
2297 /*
2298 * File daemon resource types
2299 */
2300 {CFG_TYPE_CIPHER, "ENCRYPTION_CIPHER", "Encryption Cipher"},
2301
2302 {0, NULL, NULL}};
2303
GetDatatype(int number)2304 DatatypeName* GetDatatype(int number)
2305 {
2306 int size = sizeof(datatype_names) / sizeof(datatype_names[0]);
2307
2308 if (number >= size) {
2309 /*
2310 * Last entry of array is a dummy entry
2311 */
2312 number = size - 1;
2313 }
2314
2315 return &(datatype_names[number]);
2316 }
2317
DatatypeToString(int type)2318 const char* DatatypeToString(int type)
2319 {
2320 for (int i = 0; datatype_names[i].name; i++) {
2321 if (datatype_names[i].number == type) { return datatype_names[i].name; }
2322 }
2323
2324 return "unknown";
2325 }
2326
DatatypeToDescription(int type)2327 const char* DatatypeToDescription(int type)
2328 {
2329 for (int i = 0; datatype_names[i].name; i++) {
2330 if (datatype_names[i].number == type) {
2331 return datatype_names[i].description;
2332 }
2333 }
2334
2335 return NULL;
2336 }
2337