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