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