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