1 /*
2    BAREOS® - Backup Archiving REcovery Open Sourced
3 
4    Copyright (C) 2000-2012 Free Software Foundation Europe e.V.
5    Copyright (C) 2011-2016 Planets Communications B.V.
6    Copyright (C) 2013-2020 Bareos GmbH & Co. KG
7 
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version three of the GNU Affero General Public
10    License as published by the Free Software Foundation and included
11    in the file LICENSE.
12 
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    Affero General Public License for more details.
17 
18    You should have received a copy of the GNU Affero General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22 */
23 /*
24  * Kern Sibbald, March MM
25  */
26 /**
27  * @file
28  * the main program
29  */
30 
31 #include "include/bareos.h"
32 #include "cats/cats_backends.h"
33 #include "cats/sql.h"
34 #include "cats/sql_pooling.h"
35 #include "dird.h"
36 #include "dird_globals.h"
37 #include "dird/check_catalog.h"
38 #include "dird/job.h"
39 #include "dird/scheduler.h"
40 #include "dird/socket_server.h"
41 #include "dird/stats.h"
42 #include "lib/daemon.h"
43 #include "lib/berrno.h"
44 #include "lib/edit.h"
45 #include "lib/tls_openssl.h"
46 #include "lib/bsignal.h"
47 #include "lib/daemon.h"
48 #include "lib/parse_conf.h"
49 #include "lib/thread_specific_data.h"
50 #include "lib/util.h"
51 #include "lib/watchdog.h"
52 
53 #ifndef HAVE_REGEX_H
54 #include "lib/bregex.h"
55 #else
56 #include <regex.h>
57 #endif
58 #ifdef HAVE_DIRENT_H
59 #include <dirent.h>
60 #define NAMELEN(dirent) (strlen((dirent)->d_name))
61 #endif
62 #ifndef HAVE_READDIR_R
63 int Readdir_r(DIR* dirp, struct dirent* entry, struct dirent** result);
64 #endif
65 
66 using namespace directordaemon;
67 
68 /* Forward referenced subroutines */
69 namespace directordaemon {
70 
71 #if !defined(HAVE_WIN32)
72 static
73 #endif
74     void
75     TerminateDird(int sig);
76 }  // namespace directordaemon
77 
78 static bool CheckResources();
79 static bool InitializeSqlPooling(void);
80 static void CleanUpOldFiles();
81 static bool InitSighandlerSighup();
82 static JobControlRecord* PrepareJobToRun(const char* job_name);
83 
84 /* Exported subroutines */
85 extern bool ParseDirConfig(const char* configfile, int exit_code);
86 extern void PrintMessage(void* sock, const char* fmt, ...);
87 
88 /* Imported subroutines */
89 void StoreJobtype(LEX* lc, ResourceItem* item, int index, int pass);
90 void StoreProtocoltype(LEX* lc, ResourceItem* item, int index, int pass);
91 void StoreLevel(LEX* lc, ResourceItem* item, int index, int pass);
92 void StoreReplace(LEX* lc, ResourceItem* item, int index, int pass);
93 void StoreMigtype(LEX* lc, ResourceItem* item, int index, int pass);
94 void InitDeviceResources();
95 
96 static char* runjob = NULL;
97 static bool background = true;
98 static bool test_config = false;
99 static alist* reload_table = NULL;
100 
101 /* Globals Imported */
102 extern ResourceItem job_items[];
103 
104 struct resource_table_reference {
105   int JobCount;
106   BareosResource** res_table;
107 };
108 
FreeSavedResources(resource_table_reference * table)109 static void FreeSavedResources(resource_table_reference* table)
110 {
111   int num = my_config->r_last_ - my_config->r_first_ + 1;
112 
113   if (!table->res_table) { return; }
114 
115   for (int j = 0; j < num; j++) {
116     my_config->FreeResourceCb_(table->res_table[j], my_config->r_first_ + j);
117   }
118   free(table->res_table);
119 }
120 
121 /**
122  * Called here at the end of every job that was hooked decrementing the active
123  * JobCount. When it goes to zero, no one is using the associated resource
124  * table, so free it.
125  */
ReloadJobEndCb(JobControlRecord * jcr,void * ctx)126 static void ReloadJobEndCb(JobControlRecord* jcr, void* ctx)
127 {
128   int i;
129   resource_table_reference* table;
130 
131   LockJobs();
132   LockRes(my_config);
133 
134   foreach_alist_index (i, table, reload_table) {
135     if (table == (resource_table_reference*)ctx) {
136       if (table->JobCount) {
137         table->JobCount--;
138         if (table->JobCount == 0) {
139           Dmsg1(100, "Last reference to old configuration table: %#010x\n",
140                 table);
141           FreeSavedResources(table);
142           reload_table->remove(i);
143           free(table);
144           break;
145         }
146       }
147     }
148   }
149 
150   UnlockRes(my_config);
151   UnlockJobs();
152 }
153 
154 /**
155  * This allows the message handler to operate on the database by using a pointer
156  * to this function. The pointer is needed because the other daemons do not have
157  * access to the database. If the pointer is not defined (other daemons), then
158  * writing the database is disabled.
159  */
DirDbLogInsert(JobControlRecord * jcr,utime_t mtime,const char * msg)160 static bool DirDbLogInsert(JobControlRecord* jcr,
161                            utime_t mtime,
162                            const char* msg)
163 {
164   int length;
165   char ed1[50];
166   char dt[MAX_TIME_LENGTH];
167   PoolMem query(PM_MESSAGE), esc_msg(PM_MESSAGE);
168 
169   if (!jcr || !jcr->db || !jcr->db->IsConnected()) { return false; }
170   length = strlen(msg);
171   esc_msg.check_size(length * 2 + 1);
172   jcr->db->EscapeString(jcr, esc_msg.c_str(), msg, length);
173 
174   bstrutime(dt, sizeof(dt), mtime);
175   Mmsg(query, "INSERT INTO Log (JobId, Time, LogText) VALUES (%s,'%s','%s')",
176        edit_int64(jcr->JobId, ed1), dt, esc_msg.c_str());
177 
178   return jcr->db->SqlQuery(query.c_str());
179 }
180 
usage()181 static void usage()
182 {
183   kBareosVersionStrings.PrintCopyrightWithFsfAndPlanets(stderr, 2000);
184   fprintf(
185       stderr,
186       _("Usage: bareos-dir [options]\n"
187         "        -c <path>   use <path> as configuration file or directory\n"
188         "        -d <nn>     set debug level to <nn>\n"
189         "        -dt         print timestamp in debug output\n"
190         "        -f          run in foreground (for debugging)\n"
191         "        -g <group>  run as group <group>\n"
192         "        -m          print kaboom output (for debugging)\n"
193         "        -r <job>    run <job> now\n"
194         "        -s          no signals (for debugging)\n"
195         "        -t          test - read configuration and exit\n"
196         "        -u <user>   run as user <user>\n"
197         "        -v          verbose user messages\n"
198         "        -xc         print configuration and exit\n"
199         "        -xs         print configuration file schema in JSON format "
200         "and exit\n"
201         "        -?          print this message.\n"
202         "\n"));
203 
204   exit(1);
205 }
206 
207 
208 /*********************************************************************
209  *
210  *         Main BAREOS Director Server program
211  *
212  */
213 #if defined(HAVE_WIN32)
214 #define main BareosMain
215 #endif
216 
main(int argc,char * argv[])217 int main(int argc, char* argv[])
218 {
219   int ch;
220   cat_op mode;
221   bool no_signals = false;
222   bool export_config = false;
223   bool export_config_schema = false;
224   char* uid = NULL;
225   char* gid = NULL;
226 
227   setlocale(LC_ALL, "");
228   tzset();
229   bindtextdomain("bareos", LOCALEDIR);
230   textdomain("bareos");
231 
232   InitStackDump();
233   MyNameIs(argc, argv, "bareos-dir");
234   InitMsg(NULL, NULL); /* initialize message handler */
235   daemon_start_time = time(NULL);
236 
237   console_command = RunConsoleCommand;
238 
239   while ((ch = getopt(argc, argv, "c:d:fg:mr:stu:vx:z:?")) != -1) {
240     switch (ch) {
241       case 'c': /* specify config file */
242         if (configfile != NULL) { free(configfile); }
243         configfile = strdup(optarg);
244         break;
245 
246       case 'd': /* set debug level */
247         if (*optarg == 't') {
248           dbg_timestamp = true;
249         } else {
250           debug_level = atoi(optarg);
251           if (debug_level <= 0) { debug_level = 1; }
252         }
253         Dmsg1(10, "Debug level = %d\n", debug_level);
254         break;
255 
256       case 'f': /* run in foreground */
257         background = false;
258         break;
259 
260       case 'g': /* set group id */
261         gid = optarg;
262         break;
263 
264       case 'm': /* print kaboom output */
265         prt_kaboom = true;
266         break;
267 
268       case 'r': /* run job */
269         if (runjob != NULL) { free(runjob); }
270         if (optarg) { runjob = strdup(optarg); }
271         break;
272 
273       case 's': /* turn off signals */
274         no_signals = true;
275         break;
276 
277       case 't': /* test config */
278         test_config = true;
279         break;
280 
281       case 'u': /* set uid */
282         uid = optarg;
283         break;
284 
285       case 'v': /* verbose */
286         verbose++;
287         break;
288 
289       case 'x': /* export configuration/schema and exit */
290         if (*optarg == 's') {
291           export_config_schema = true;
292         } else if (*optarg == 'c') {
293           export_config = true;
294         } else {
295           usage();
296         }
297         break;
298 
299       case 'z': /* switch network debugging on */
300         if (!BnetDump::EvaluateCommandLineArgs(optarg)) { exit(1); }
301         break;
302 
303       case '?':
304       default:
305         usage();
306         break;
307     }
308   }
309   argc -= optind;
310   argv += optind;
311 
312   if (!no_signals) { InitSignals(TerminateDird); }
313 
314   if (argc) {
315     if (configfile != NULL) { free(configfile); }
316     configfile = strdup(*argv);
317     argc--;
318     argv++;
319   }
320   if (argc) { usage(); }
321 
322   /*
323    * See if we want to drop privs.
324    */
325   if (geteuid() == 0) {
326     drop(uid, gid, false); /* reduce privileges if requested */
327   }
328 
329   if (export_config_schema) {
330     PoolMem buffer;
331 
332     my_config = InitDirConfig(configfile, M_ERROR_TERM);
333     PrintConfigSchemaJson(buffer);
334     printf("%s\n", buffer.c_str());
335     goto bail_out;
336   }
337 
338   my_config = InitDirConfig(configfile, M_ERROR_TERM);
339   my_config->ParseConfig();
340 
341   if (export_config) {
342     my_config->DumpResources(PrintMessage, NULL);
343     goto bail_out;
344   }
345 
346   if (!test_config) { /* we don't need to do this block in test mode */
347     if (background) {
348       daemon_start();
349       InitStackDump(); /* grab new pid */
350     }
351   }
352   if (InitCrypto() != 0) {
353     Jmsg((JobControlRecord*)NULL, M_ERROR_TERM, 0,
354          _("Cryptography library initialization failed.\n"));
355     goto bail_out;
356   }
357 
358   if (!CheckResources()) {
359     Jmsg((JobControlRecord*)NULL, M_ERROR_TERM, 0,
360          _("Please correct the configuration in %s\n"),
361          my_config->get_base_config_path().c_str());
362     goto bail_out;
363   }
364 
365   if (!test_config) { /* we don't need to do this block in test mode */
366     /* Create pid must come after we are a daemon -- so we have our final pid */
367     CreatePidFile(me->pid_directory, "bareos-dir",
368                   GetFirstPortHostOrder(me->DIRaddrs));
369     ReadStateFile(me->working_directory, "bareos-dir",
370                   GetFirstPortHostOrder(me->DIRaddrs));
371   }
372 
373   SetJcrInThreadSpecificData(nullptr);
374   SetThreadConcurrency(me->MaxConcurrentJobs * 2 + 4 /* UA */ +
375                        5 /* sched+watchdog+jobsvr+misc */);
376 
377 #if defined(HAVE_DYNAMIC_CATS_BACKENDS)
378   for (const auto& backend_dir : me->backend_directories) {
379     Dmsg1(100, "backend path: %s\n", backend_dir.c_str());
380   }
381 
382   DbSetBackendDirs(me->backend_directories);
383 #endif
384   LoadDirPlugins(me->plugin_directory, me->plugin_names);
385 
386   /*
387    * If we are in testing mode, we don't try to fix the catalog
388    */
389   mode = (test_config) ? CHECK_CONNECTION : UPDATE_AND_FIX;
390 
391   if (!CheckCatalog(mode)) {
392     Jmsg((JobControlRecord*)NULL, M_ERROR_TERM, 0,
393          _("Please correct the configuration in %s\n"),
394          my_config->get_base_config_path().c_str());
395     goto bail_out;
396   }
397 
398   if (test_config) { TerminateDird(0); }
399 
400   if (!InitializeSqlPooling()) {
401     Jmsg((JobControlRecord*)NULL, M_ERROR_TERM, 0,
402          _("Please correct the configuration in %s\n"),
403          my_config->get_base_config_path().c_str());
404     goto bail_out;
405   }
406 
407   MyNameIs(0, NULL, me->resource_name_); /* set user defined name */
408 
409   CleanUpOldFiles();
410 
411   SetDbLogInsertCallback(DirDbLogInsert);
412 
413   InitSighandlerSighup();
414 
415   InitConsoleMsg(working_directory);
416 
417   StartWatchdog(); /* start network watchdog thread */
418 
419   InitJcrChain();
420   if (me->jcr_watchdog_time) {
421     InitJcrSubsystem(
422         me->jcr_watchdog_time); /* start JobControlRecord watchdogs etc. */
423   }
424 
425   InitJobServer(me->MaxConcurrentJobs);
426 
427   DbgJcrAddHook(
428       DbDebugPrint); /* used to debug BareosDb connexion after fatal signal */
429 
430   //   InitDeviceResources();
431 
432   StartStatisticsThread();
433 
434   Dmsg0(200, "Start UA server\n");
435   if (!StartSocketServer(me->DIRaddrs)) { TerminateDird(0); }
436 
437   Dmsg0(200, "wait for next job\n");
438 
439   if (runjob) {
440     JobControlRecord* jcr = PrepareJobToRun(runjob);
441     if (jcr) { ExecuteJob(jcr); }
442   } else {
443     Scheduler::GetMainScheduler().Run();
444   }
445 
446 bail_out:
447   TerminateDird(0);
448   return 0;
449 }
450 
451 /**
452  * Cleanup and then exit
453  *
454  */
455 namespace directordaemon {
456 #if !defined(HAVE_WIN32)
457 static
458 #endif
459     void
TerminateDird(int sig)460     TerminateDird(int sig)
461 {
462   static bool is_reloading = false;
463 
464   if (is_reloading) {  /* avoid recursive termination problems */
465     Bmicrosleep(2, 0); /* yield */
466     exit(1);
467   }
468 
469   is_reloading = true;
470   debug_level = 0; /* turn off debug */
471 
472   DestroyConfigureUsageString();
473   StopSocketServer();
474   StopStatisticsThread();
475   StopWatchdog();
476   DbSqlPoolDestroy();
477   DbFlushBackends();
478   UnloadDirPlugins();
479   if (!test_config && me) { /* we don't need to do this block in test mode */
480     WriteStateFile(me->working_directory, "bareos-dir",
481                    GetFirstPortHostOrder(me->DIRaddrs));
482     DeletePidFile(me->pid_directory, "bareos-dir",
483                   GetFirstPortHostOrder(me->DIRaddrs));
484   }
485   Scheduler::GetMainScheduler().Terminate();
486   TermJobServer();
487 
488   if (runjob) { free(runjob); }
489   if (configfile != NULL) { free(configfile); }
490   if (debug_level > 5) { PrintMemoryPoolStats(); }
491   if (my_config) {
492     delete my_config;
493     my_config = NULL;
494   }
495 
496   TermMsg(); /* Terminate message handler */
497   CleanupCrypto();
498   CloseMemoryPool(); /* release free memory in pool */
499 
500   exit(sig);
501 }
502 } /* namespace directordaemon */
503 
504 /**
505  * If we get here, we have received a SIGHUP, which means to reread our
506  * configuration file.
507  */
508 #if !defined(HAVE_WIN32)
SighandlerReloadConfig(int sig,siginfo_t * siginfo,void * ptr)509 extern "C" void SighandlerReloadConfig(int sig, siginfo_t* siginfo, void* ptr)
510 {
511   static bool is_reloading = false;
512 
513   if (is_reloading) {
514     /*
515      * Note: don't use Jmsg here, as it could produce a race condition
516      * on multiple parallel reloads
517      */
518     Qmsg(NULL, M_ERROR, 0, _("Already reloading. Request ignored.\n"));
519     return;
520   }
521   is_reloading = true;
522   DoReloadConfig();
523   is_reloading = false;
524 }
525 #endif
526 
InitSighandlerSighup()527 static bool InitSighandlerSighup()
528 {
529   bool retval = false;
530 #if !defined(HAVE_WIN32)
531   sigset_t block_mask;
532   struct sigaction action = {};
533 
534   /*
535    *  while handling SIGHUP signal,
536    *  ignore further SIGHUP signals.
537    */
538   sigemptyset(&block_mask);
539   sigaddset(&block_mask, SIGHUP);
540 
541   action.sa_sigaction = SighandlerReloadConfig;
542   action.sa_mask = block_mask;
543   action.sa_flags = SA_SIGINFO;
544   sigaction(SIGHUP, &action, NULL);
545 
546   retval = true;
547 #endif
548   return retval;
549 }
550 
551 namespace directordaemon {
DoReloadConfig()552 bool DoReloadConfig()
553 {
554   static bool is_reloading = false;
555   bool reloaded = false;
556   resource_table_reference prev_config;
557 
558   if (is_reloading) {
559     /*
560      * Note: don't use Jmsg here, as it could produce a race condition
561      * on multiple parallel reloads
562      */
563     Qmsg(NULL, M_ERROR, 0, _("Already reloading. Request ignored.\n"));
564     return false;
565   }
566   is_reloading = true;
567 
568   StopStatisticsThread();
569 
570   LockJobs();
571   LockRes(my_config);
572 
573   DbSqlPoolFlush();
574 
575   prev_config.res_table = my_config->SaveResources();
576   prev_config.JobCount = 0;
577 
578   Dmsg0(100, "Reloading config file\n");
579 
580   my_config->err_type_ = M_ERROR;
581   bool ok = my_config->ParseConfig();
582 
583   if (!ok || !CheckResources() || !CheckCatalog(UPDATE_CATALOG) ||
584       !InitializeSqlPooling()) {
585     Jmsg(NULL, M_ERROR, 0, _("Please correct the configuration in %s\n"),
586          my_config->get_base_config_path().c_str());
587     Jmsg(NULL, M_ERROR, 0, _("Resetting to previous configuration.\n"));
588 
589     resource_table_reference temp_config;
590     temp_config.res_table = my_config->SaveResources();
591 
592     int num_rcodes = my_config->r_last_ - my_config->r_first_ + 1;
593     for (int i = 0; i < num_rcodes; i++) {
594       // restore original config
595       my_config->res_head_[i] = prev_config.res_table[i];
596     }
597 
598     // me is changed above by CheckResources()
599     me = (DirectorResource*)my_config->GetNextRes(R_DIRECTOR, NULL);
600     my_config->own_resource_ = me;
601 
602     FreeSavedResources(&temp_config);
603     goto bail_out;
604 
605   } else {  // parse config ok
606 
607     JobControlRecord* jcr;
608     int num_running_jobs = 0;
609     resource_table_reference* new_table = NULL;
610 
611     Scheduler::GetMainScheduler().ClearQueue();
612     foreach_jcr (jcr) {
613       if (jcr->getJobType() != JT_SYSTEM) {
614         if (!new_table) {
615           new_table = (resource_table_reference*)malloc(
616               sizeof(resource_table_reference));
617           memcpy(new_table, &prev_config, sizeof(resource_table_reference));
618         }
619         new_table->JobCount++;
620         RegisterJobEndCallback(jcr, ReloadJobEndCb, (void*)new_table);
621         num_running_jobs++;
622       }
623     }
624     endeach_jcr(jcr);
625     reloaded = true;
626 
627     SetWorkingDirectory(me->working_directory);
628     Dmsg0(10, "Director's configuration file reread.\n");
629 
630     if (num_running_jobs > 0) {
631       if (!reload_table) { reload_table = new alist(10, not_owned_by_alist); }
632       reload_table->push(new_table);
633     } else {  // no jobs running
634       FreeSavedResources(&prev_config);
635     }
636     StartStatisticsThread();
637   }
638 
639 bail_out:
640   UnlockRes(my_config);
641   UnlockJobs();
642   is_reloading = false;
643   return reloaded;
644 }
645 
646 } /* namespace directordaemon */
647 
648 /*
649  * See if two storage definitions point to the same Storage Daemon.
650  *
651  * We compare:
652  *  - address
653  *  - SDport
654  *  - password
655  */
IsSameStorageDaemon(StorageResource * store1,StorageResource * store2)656 static inline bool IsSameStorageDaemon(StorageResource* store1,
657                                        StorageResource* store2)
658 {
659   return store1->SDport == store2->SDport &&
660          Bstrcasecmp(store1->address, store2->address) &&
661          Bstrcasecmp(store1->password_.value, store2->password_.value);
662 }
663 
664 /**
665  * Make a quick check to see that we have all the
666  * resources needed.
667  *
668  *  **** FIXME **** this routine could be a lot more
669  *   intelligent and comprehensive.
670  */
CheckResources()671 static bool CheckResources()
672 {
673   bool OK = true;
674   JobResource* job;
675   const std::string& configfile = my_config->get_base_config_path();
676 
677   LockRes(my_config);
678 
679   job = (JobResource*)my_config->GetNextRes(R_JOB, NULL);
680   me = (DirectorResource*)my_config->GetNextRes(R_DIRECTOR, NULL);
681   my_config->own_resource_ = me;
682   if (!me) {
683     Jmsg(NULL, M_FATAL, 0,
684          _("No Director resource defined in %s\n"
685            "Without that I don't know who I am :-(\n"),
686          configfile.c_str());
687     OK = false;
688     goto bail_out;
689   } else {
690     /*
691      * Sanity check.
692      */
693     if (me->MaxConsoleConnections > me->MaxConnections) {
694       me->MaxConnections = me->MaxConsoleConnections + 10;
695     }
696 
697     my_config->omit_defaults_ = me->omit_defaults;
698     SetWorkingDirectory(me->working_directory);
699 
700     /*
701      * See if message resource is specified.
702      */
703     if (!me->messages) {
704       me->messages = (MessagesResource*)my_config->GetNextRes(R_MSGS, NULL);
705       if (!me->messages) {
706         Jmsg(NULL, M_FATAL, 0, _("No Messages resource defined in %s\n"),
707              configfile.c_str());
708         OK = false;
709         goto bail_out;
710       }
711     }
712 
713     /*
714      * When the user didn't force us we optimize for size.
715      */
716     if (!me->optimize_for_size && !me->optimize_for_speed) {
717       me->optimize_for_size = true;
718     } else if (me->optimize_for_size && me->optimize_for_speed) {
719       Jmsg(NULL, M_FATAL, 0,
720            _("Cannot optimize for speed and size define only one in %s\n"),
721            configfile.c_str());
722       OK = false;
723       goto bail_out;
724     }
725 
726     if (my_config->GetNextRes(R_DIRECTOR, (BareosResource*)me) != NULL) {
727       Jmsg(NULL, M_FATAL, 0, _("Only one Director resource permitted in %s\n"),
728            configfile.c_str());
729       OK = false;
730       goto bail_out;
731     }
732 
733     if (me->IsTlsConfigured()) {
734       if (!have_tls) {
735         Jmsg(NULL, M_FATAL, 0,
736              _("TLS required but not compiled into BAREOS.\n"));
737         OK = false;
738         goto bail_out;
739       }
740     }
741   }
742 
743   if (!job) {
744     Jmsg(NULL, M_FATAL, 0, _("No Job records defined in %s\n"),
745          configfile.c_str());
746     OK = false;
747     goto bail_out;
748   }
749 
750   if (!PopulateDefs()) {
751     OK = false;
752     goto bail_out;
753   }
754 
755   /*
756    * Loop over Jobs
757    */
758   foreach_res (job, R_JOB) {
759     if (job->MaxFullConsolidations && job->JobType != JT_CONSOLIDATE) {
760       Jmsg(NULL, M_FATAL, 0,
761            _("MaxFullConsolidations configured in job %s which is not of job "
762              "type \"consolidate\" in file %s\n"),
763            job->resource_name_, configfile.c_str());
764       OK = false;
765       goto bail_out;
766     }
767 
768     if (job->JobType != JT_BACKUP &&
769         (job->AlwaysIncremental || job->AlwaysIncrementalJobRetention ||
770          job->AlwaysIncrementalKeepNumber ||
771          job->AlwaysIncrementalMaxFullAge)) {
772       Jmsg(NULL, M_FATAL, 0,
773            _("AlwaysIncremental configured in job %s which is not of job type "
774              "\"backup\" in file %s\n"),
775            job->resource_name_, configfile.c_str());
776       OK = false;
777       goto bail_out;
778     }
779   }
780 
781   ConsoleResource* cons;
782   foreach_res (cons, R_CONSOLE) {
783     if (cons->IsTlsConfigured()) {
784       if (!have_tls) {
785         Jmsg(NULL, M_FATAL, 0,
786              _("TLS required but not configured in BAREOS.\n"));
787         OK = false;
788         goto bail_out;
789       }
790     }
791   }
792 
793   me->subscriptions_used = 0;
794   ClientResource* client;
795   foreach_res (client, R_CLIENT) {
796     /*
797      * Count the number of clients
798      *
799      * Only used as indication not an enforced limit.
800      */
801     me->subscriptions_used++;
802 
803     if (client->IsTlsConfigured()) {
804       if (!have_tls) {
805         Jmsg(NULL, M_FATAL, 0, _("TLS required but not configured.\n"));
806         OK = false;
807         goto bail_out;
808       }
809     }
810   }
811 
812   StorageResource *store, *nstore;
813   foreach_res (store, R_STORAGE) {
814     if (store->IsTlsConfigured()) {
815       if (!have_tls) {
816         Jmsg(NULL, M_FATAL, 0, _("TLS required but not configured.\n"));
817         OK = false;
818         goto bail_out;
819       }
820     }
821 
822     /*
823      * If we collect statistics on this SD make sure any other entry pointing to
824      * the same SD does not collect statistics otherwise we collect the same
825      * data multiple times.
826      */
827     if (store->collectstats) {
828       nstore = store;
829       while ((nstore = (StorageResource*)my_config->GetNextRes(
830                   R_STORAGE, (BareosResource*)nstore))) {
831         if (IsSameStorageDaemon(store, nstore) && nstore->collectstats) {
832           nstore->collectstats = false;
833           Dmsg1(200,
834                 _("Disabling collectstats for storage \"%s\""
835                   " as other storage already collects from this SD.\n"),
836                 nstore->resource_name_);
837         }
838       }
839     }
840   }
841 
842   if (OK) {
843     CloseMsg(NULL);              /* close temp message handler */
844     InitMsg(NULL, me->messages); /* open daemon message handler */
845     if (me->secure_erase_cmdline) {
846       SetSecureEraseCmdline(me->secure_erase_cmdline);
847     }
848     if (me->log_timestamp_format) {
849       SetLogTimestampFormat(me->log_timestamp_format);
850     }
851   }
852 
853 bail_out:
854   UnlockRes(my_config);
855   return OK;
856 }
857 
858 /**
859  * Initialize the sql pooling.
860  */
InitializeSqlPooling(void)861 static bool InitializeSqlPooling(void)
862 {
863   bool retval = true;
864   CatalogResource* catalog;
865 
866   foreach_res (catalog, R_CATALOG) {
867     if (!db_sql_pool_initialize(
868             catalog->db_driver, catalog->db_name, catalog->db_user,
869             catalog->db_password.value, catalog->db_address, catalog->db_port,
870             catalog->db_socket, catalog->disable_batch_insert,
871             catalog->try_reconnect, catalog->exit_on_fatal,
872             catalog->pooling_min_connections, catalog->pooling_max_connections,
873             catalog->pooling_increment_connections,
874             catalog->pooling_idle_timeout, catalog->pooling_validate_timeout)) {
875       Jmsg(NULL, M_FATAL, 0,
876            _("Could not setup sql pooling for Catalog \"%s\", database "
877              "\"%s\".\n"),
878            catalog->resource_name_, catalog->db_name);
879       retval = false;
880       goto bail_out;
881     }
882   }
883 
884 bail_out:
885   return retval;
886 }
887 
PrepareJobToRun(const char * job_name)888 static JobControlRecord* PrepareJobToRun(const char* job_name)
889 {
890   JobResource* job =
891       static_cast<JobResource*>(my_config->GetResWithName(R_JOB, job_name));
892   if (!job) {
893     Emsg1(M_ERROR, 0, _("Job %s not found\n"), job_name);
894     return nullptr;
895   }
896   Dmsg1(5, "Found job_name %s\n", job_name);
897   JobControlRecord* jcr = NewDirectorJcr();
898   SetJcrDefaults(jcr, job);
899   return jcr;
900 }
901 
CleanUpOldFiles()902 static void CleanUpOldFiles()
903 {
904   DIR* dp;
905   struct dirent* result;
906 #ifdef USE_READDIR_R
907   struct dirent* entry;
908 #endif
909   int rc, name_max;
910   int my_name_len = strlen(my_name);
911   int len = strlen(me->working_directory);
912   POOLMEM* cleanup = GetPoolMemory(PM_MESSAGE);
913   POOLMEM* basename = GetPoolMemory(PM_MESSAGE);
914   regex_t preg1{};
915   char prbuf[500];
916   BErrNo be;
917 
918   /* Exclude spaces and look for .mail or .restore.xx.bsr files */
919   const char* pat1 = "^[^ ]+\\.(restore\\.[^ ]+\\.bsr|mail)$";
920 
921   /* Setup working directory prefix */
922   PmStrcpy(basename, me->working_directory);
923   if (len > 0 && !IsPathSeparator(me->working_directory[len - 1])) {
924     PmStrcat(basename, "/");
925   }
926 
927   /* Compile regex expressions */
928   rc = regcomp(&preg1, pat1, REG_EXTENDED);
929   if (rc != 0) {
930     regerror(rc, &preg1, prbuf, sizeof(prbuf));
931     Pmsg2(000, _("Could not compile regex pattern \"%s\" ERR=%s\n"), pat1,
932           prbuf);
933     goto get_out2;
934   }
935 
936   name_max = pathconf(".", _PC_NAME_MAX);
937   if (name_max < 1024) { name_max = 1024; }
938 
939   if (!(dp = opendir(me->working_directory))) {
940     BErrNo be;
941     Pmsg2(000, "Failed to open working dir %s for cleanup: ERR=%s\n",
942           me->working_directory, be.bstrerror());
943     goto get_out1;
944     return;
945   }
946 
947 #ifdef USE_READDIR_R
948   entry = (struct dirent*)malloc(sizeof(struct dirent) + name_max + 1000);
949   while (1) {
950     if ((Readdir_r(dp, entry, &result) != 0) || (result == NULL)) {
951 #else
952   while (1) {
953     result = readdir(dp);
954     if (result == NULL) {
955 #endif
956 
957       break;
958     }
959     /* Exclude any name with ., .., not my_name or containing a space */
960     if (strcmp(result->d_name, ".") == 0 || strcmp(result->d_name, "..") == 0 ||
961         strncmp(result->d_name, my_name, my_name_len) != 0) {
962       Dmsg1(500, "Skipped: %s\n", result->d_name);
963       continue;
964     }
965 
966     /* Unlink files that match regexes */
967     if (regexec(&preg1, result->d_name, 0, NULL, 0) == 0) {
968       PmStrcpy(cleanup, basename);
969       PmStrcat(cleanup, result->d_name);
970       Dmsg1(100, "Unlink: %s\n", cleanup);
971       SecureErase(NULL, cleanup);
972     }
973   }
974 
975 #ifdef USE_READDIR_R
976   free(entry);
977 #endif
978   closedir(dp);
979 /* Be careful to free up the correct resources */
980 get_out1:
981   regfree(&preg1);
982 get_out2:
983   FreePoolMemory(cleanup);
984   FreePoolMemory(basename);
985 }
986