1 /*
2    BAREOS® - Backup Archiving REcovery Open Sourced
3 
4    Copyright (C) 2000-2012 Free Software Foundation Europe e.V.
5    Copyright (C) 2011-2012 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, MM
25  */
26 /**
27  * @file
28  * Second generation Storage daemon.
29  *
30  * It accepts a number of simple commands from the File daemon
31  * and acts on them. When a request to append data is made,
32  * it opens a data channel and accepts data from the
33  * File daemon.
34  */
35 
36 #include "include/bareos.h"
37 #include "stored/stored.h"
38 #include "lib/crypto_cache.h"
39 #include "stored/acquire.h"
40 #include "stored/autochanger.h"
41 #include "stored/bsr.h"
42 #include "stored/device.h"
43 #include "stored/jcr_private.h"
44 #include "stored/job.h"
45 #include "stored/label.h"
46 #include "stored/ndmp_tape.h"
47 #include "stored/sd_backends.h"
48 #include "stored/sd_stats.h"
49 #include "stored/socket_server.h"
50 #include "stored/stored_globals.h"
51 #include "stored/wait.h"
52 #include "lib/berrno.h"
53 #include "lib/bsock.h"
54 #include "lib/bnet_network_dump.h"
55 #include "lib/daemon.h"
56 #include "lib/bsignal.h"
57 #include "lib/parse_conf.h"
58 #include "lib/thread_specific_data.h"
59 #include "lib/util.h"
60 #include "lib/watchdog.h"
61 #include "include/jcr.h"
62 
63 
64 namespace storagedaemon {
65 extern bool ParseSdConfig(const char* configfile, int exit_code);
66 }
67 
68 using namespace storagedaemon;
69 
70 /* Imported functions */
71 extern void PrintMessage(void* sock, const char* fmt, ...);
72 
73 /* Forward referenced functions */
74 namespace storagedaemon {
75 #if !defined(HAVE_WIN32)
76 static
77 #endif
78     void
79     TerminateStored(int sig);
80 }  // namespace storagedaemon
81 static int CheckResources();
82 static void CleanUpOldFiles();
83 
84 extern "C" void* device_initialization(void* arg);
85 
86 /* Global static variables */
87 static bool foreground = 0;
88 
usage()89 static void usage()
90 {
91   kBareosVersionStrings.PrintCopyrightWithFsfAndPlanets(stderr, 2000);
92   fprintf(
93       stderr,
94       _("Usage: bareos-sd [options]\n"
95         "        -c <path>   use <path> as configuration file or directory\n"
96         "        -d <nn>     set debug level to <nn>\n"
97         "        -dt         print timestamp in debug output\n"
98         "        -f          run in foreground (for debugging)\n"
99         "        -g <group>  run as group <group>\n"
100         "        -m          print kaboom output (for debugging)\n"
101         "        -p          proceed despite I/O errors\n"
102         "        -s          no signals (for debugging)\n"
103         "        -t          test - read configuration and exit\n"
104         "        -u <user>   run as user <user>\n"
105         "        -v          verbose user messages\n"
106         "        -xc         print configuration and exit\n"
107         "        -xs         print configuration file schema in JSON format "
108         "and exit\n"
109         "        -?          print this message.\n"
110         "\n"));
111   exit(1);
112 }
113 
114 /*********************************************************************
115  *
116  *  Main Bareos Storage Daemon
117  *
118  */
119 #if defined(HAVE_WIN32)
120 #define main BareosMain
121 #endif
122 
main(int argc,char * argv[])123 int main(int argc, char* argv[])
124 {
125   int ch;
126   bool no_signals = false;
127   bool test_config = false;
128   bool export_config = false;
129   bool export_config_schema = false;
130   pthread_t thid;
131   char* uid = NULL;
132   char* gid = NULL;
133 
134   setlocale(LC_ALL, "");
135   tzset();
136   bindtextdomain("bareos", LOCALEDIR);
137   textdomain("bareos");
138 
139   InitStackDump();
140   MyNameIs(argc, argv, "bareos-sd");
141   InitMsg(NULL, NULL);
142   daemon_start_time = time(NULL);
143 
144   /*
145    * Sanity checks
146    */
147   if (TAPE_BSIZE % B_DEV_BSIZE != 0 || TAPE_BSIZE / B_DEV_BSIZE == 0) {
148     Emsg2(M_ABORT, 0,
149           _("Tape block size (%d) not multiple of system size (%d)\n"),
150           TAPE_BSIZE, B_DEV_BSIZE);
151   }
152   if (TAPE_BSIZE != (1 << (ffs(TAPE_BSIZE) - 1))) {
153     Emsg1(M_ABORT, 0, _("Tape block size (%d) is not a power of 2\n"),
154           TAPE_BSIZE);
155   }
156 
157   while ((ch = getopt(argc, argv, "c:d:fg:mpstu:vx:z:?")) != -1) {
158     switch (ch) {
159       case 'c': /* configuration file */
160         if (configfile != NULL) { free(configfile); }
161         configfile = strdup(optarg);
162         break;
163 
164       case 'd': /* debug level */
165         if (*optarg == 't') {
166           dbg_timestamp = true;
167         } else {
168           debug_level = atoi(optarg);
169           if (debug_level <= 0) { debug_level = 1; }
170         }
171         break;
172 
173       case 'f': /* run in foreground */
174         foreground = true;
175         break;
176 
177       case 'g': /* set group id */
178         gid = optarg;
179         break;
180 
181       case 'm': /* print kaboom output */
182         prt_kaboom = true;
183         break;
184 
185       case 'p': /* proceed in spite of I/O errors */
186         forge_on = true;
187         break;
188 
189       case 's': /* no signals */
190         no_signals = true;
191         break;
192 
193       case 't':
194         test_config = true;
195         break;
196 
197       case 'u': /* set uid */
198         uid = optarg;
199         break;
200 
201       case 'v': /* verbose */
202         verbose++;
203         break;
204 
205       case 'x': /* export configuration/schema and exit */
206         if (*optarg == 's') {
207           export_config_schema = true;
208         } else if (*optarg == 'c') {
209           export_config = true;
210         } else {
211           usage();
212         }
213         break;
214 
215       case 'z': /* switch network debugging on */
216         if (!BnetDump::EvaluateCommandLineArgs(optarg)) { exit(1); }
217         break;
218 
219       case '?':
220       default:
221         usage();
222         break;
223     }
224   }
225   argc -= optind;
226   argv += optind;
227 
228   if (!no_signals) { InitSignals(TerminateStored); }
229 
230   if (argc) {
231     if (configfile != NULL) { free(configfile); }
232     configfile = strdup(*argv);
233     argc--;
234     argv++;
235   }
236   if (argc) { usage(); }
237 
238   /*
239    * See if we want to drop privs.
240    */
241   if (geteuid() == 0) { drop(uid, gid, false); }
242 
243   if (export_config_schema) {
244     PoolMem buffer;
245 
246     my_config = InitSdConfig(configfile, M_ERROR_TERM);
247     PrintConfigSchemaJson(buffer);
248     printf("%s\n", buffer.c_str());
249     goto bail_out;
250   }
251 
252   my_config = InitSdConfig(configfile, M_ERROR_TERM);
253   ParseSdConfig(configfile, M_ERROR_TERM);
254 
255   if (export_config) {
256     my_config->DumpResources(PrintMessage, NULL);
257     goto bail_out;
258   }
259 
260   if (!foreground && !test_config) {
261     daemon_start();  /* become daemon */
262     InitStackDump(); /* pick up new pid */
263   }
264 
265   if (InitCrypto() != 0) {
266     Jmsg((JobControlRecord*)NULL, M_ERROR_TERM, 0,
267          _("Cryptography library initialization failed.\n"));
268   }
269 
270   if (!CheckResources()) {
271     Jmsg((JobControlRecord*)NULL, M_ERROR_TERM, 0,
272          _("Please correct the configuration in %s\n"),
273          my_config->get_base_config_path().c_str());
274   }
275 
276   InitReservationsLock();
277 
278   if (test_config) { TerminateStored(0); }
279 
280   MyNameIs(0, (char**)NULL, me->resource_name_); /* Set our real name */
281 
282   CreatePidFile(me->pid_directory, "bareos-sd",
283                 GetFirstPortHostOrder(me->SDaddrs));
284   ReadStateFile(me->working_directory, "bareos-sd",
285                 GetFirstPortHostOrder(me->SDaddrs));
286   ReadCryptoCache(me->working_directory, "bareos-sd",
287                   GetFirstPortHostOrder(me->SDaddrs));
288 
289   SetJcrInThreadSpecificData(nullptr);
290 
291   /*
292    * Make sure on Solaris we can run concurrent, watch dog + servers + misc
293    */
294   SetThreadConcurrency(me->MaxConcurrentJobs * 2 + 4);
295 
296   LoadSdPlugins(me->plugin_directory, me->plugin_names);
297 
298   CleanUpOldFiles();
299 
300   /* Ensure that Volume Session Time and Id are both
301    * set and are both non-zero.
302    */
303   vol_session_time = (uint32_t)daemon_start_time;
304   if (vol_session_time == 0) { /* paranoid */
305     Jmsg0(NULL, M_ABORT, 0, _("Volume Session Time is ZERO!\n"));
306   }
307 
308   /*
309    * Start the device allocation thread
310    */
311   CreateVolumeLists(); /* do before device_init */
312   if (pthread_create(&thid, NULL, device_initialization, NULL) != 0) {
313     BErrNo be;
314     Emsg1(M_ABORT, 0, _("Unable to create thread. ERR=%s\n"), be.bstrerror());
315   }
316 
317   InitJcrChain();
318   StartWatchdog(); /* start watchdog thread */
319   if (me->jcr_watchdog_time) {
320     InitJcrSubsystem(
321         me->jcr_watchdog_time); /* start JobControlRecord watchdogs etc. */
322   }
323 
324   StartStatisticsThread();
325 
326 #if HAVE_NDMP
327   /*
328    * Separate thread that handles NDMP connections
329    */
330   if (me->ndmp_enable) {
331     StartNdmpThreadServer(me->NDMPaddrs, me->MaxConnections);
332   }
333 #endif
334 
335   /*
336    * Single server used for Director/Storage and File daemon
337    */
338   StartSocketServer(me->SDaddrs);
339 
340   /* to keep compiler quiet */
341   TerminateStored(0);
342 
343 bail_out:
344   return 0;
345 }
346 
347 /* Check Configuration file for necessary info */
CheckResources()348 static int CheckResources()
349 {
350   bool OK = true;
351   const std::string& configfile = my_config->get_base_config_path();
352 
353   if (my_config->GetNextRes(R_STORAGE, (BareosResource*)me) != NULL) {
354     Jmsg1(NULL, M_ERROR, 0, _("Only one Storage resource permitted in %s\n"),
355           configfile.c_str());
356     OK = false;
357   }
358 
359   if (my_config->GetNextRes(R_DIRECTOR, NULL) == NULL) {
360     Jmsg1(NULL, M_ERROR, 0,
361           _("No Director resource defined in %s. Cannot continue.\n"),
362           configfile.c_str());
363     OK = false;
364   }
365 
366   if (my_config->GetNextRes(R_DEVICE, NULL) == NULL) {
367     Jmsg1(NULL, M_ERROR, 0,
368           _("No Device resource defined in %s. Cannot continue.\n"),
369           configfile.c_str());
370     OK = false;
371   }
372 
373   /*
374    * Sanity check.
375    */
376   if (me->MaxConnections < ((2 * me->MaxConcurrentJobs) + 2)) {
377     me->MaxConnections = (2 * me->MaxConcurrentJobs) + 2;
378   }
379 
380   if (!me->messages) {
381     me->messages = (MessagesResource*)my_config->GetNextRes(R_MSGS, NULL);
382     if (!me->messages) {
383       Jmsg1(NULL, M_ERROR, 0,
384             _("No Messages resource defined in %s. Cannot continue.\n"),
385             configfile.c_str());
386       OK = false;
387     }
388   }
389 
390   if (!me->working_directory) {
391     Jmsg1(NULL, M_ERROR, 0,
392           _("No Working Directory defined in %s. Cannot continue.\n"),
393           configfile.c_str());
394     OK = false;
395   }
396 
397   StorageResource* store = me;
398   if (store->IsTlsConfigured()) {
399     if (!have_tls) {
400       Jmsg(NULL, M_FATAL, 0, _("TLS required but not compiled into Bareos.\n"));
401       OK = false;
402     }
403   }
404 
405   DeviceResource* device;
406   foreach_res (device, R_DEVICE) {
407     if (device->drive_crypto_enabled && BitIsSet(CAP_LABEL, device->cap_bits)) {
408       Jmsg(NULL, M_FATAL, 0,
409            _("LabelMedia enabled is incompatible with tape crypto on Device "
410              "\"%s\" in %s.\n"),
411            device->resource_name_, configfile.c_str());
412       OK = false;
413     }
414   }
415 
416   if (OK) { OK = InitAutochangers(); }
417 
418   if (OK) {
419     CloseMsg(NULL);              /* close temp message handler */
420     InitMsg(NULL, me->messages); /* open daemon message handler */
421     SetWorkingDirectory(me->working_directory);
422     if (me->secure_erase_cmdline) {
423       SetSecureEraseCmdline(me->secure_erase_cmdline);
424     }
425     if (me->log_timestamp_format) {
426       SetLogTimestampFormat(me->log_timestamp_format);
427     }
428   }
429 
430   return OK;
431 }
432 
433 /**
434  * Remove old .spool files written by me from the working directory.
435  */
CleanUpOldFiles()436 static void CleanUpOldFiles()
437 {
438   DIR* dp;
439   struct dirent* result;
440 #ifdef USE_READDIR_R
441   struct dirent* entry;
442 #endif
443   int rc, name_max;
444   int my_name_len = strlen(my_name);
445   int len = strlen(me->working_directory);
446   POOLMEM* cleanup = GetPoolMemory(PM_MESSAGE);
447   POOLMEM* basename = GetPoolMemory(PM_MESSAGE);
448   regex_t preg1{};
449   char prbuf[500];
450   BErrNo be;
451 
452   /* Look for .spool files but don't allow spaces */
453   const char* pat1 = "^[^ ]+\\.spool$";
454 
455   /* Setup working directory prefix */
456   PmStrcpy(basename, me->working_directory);
457   if (len > 0 && !IsPathSeparator(me->working_directory[len - 1])) {
458     PmStrcat(basename, "/");
459   }
460 
461   /* Compile regex expressions */
462   rc = regcomp(&preg1, pat1, REG_EXTENDED);
463   if (rc != 0) {
464     regerror(rc, &preg1, prbuf, sizeof(prbuf));
465     Pmsg2(000, _("Could not compile regex pattern \"%s\" ERR=%s\n"), pat1,
466           prbuf);
467     goto get_out2;
468   }
469 
470   name_max = pathconf(".", _PC_NAME_MAX);
471   if (name_max < 1024) { name_max = 1024; }
472 
473   if (!(dp = opendir(me->working_directory))) {
474     BErrNo be;
475     Pmsg2(000, "Failed to open working dir %s for cleanup: ERR=%s\n",
476           me->working_directory, be.bstrerror());
477     goto get_out1;
478   }
479 
480 #ifdef USE_READDIR_R
481   entry = (struct dirent*)malloc(sizeof(struct dirent) + name_max + 1000);
482   while (1) {
483     if ((Readdir_r(dp, entry, &result) != 0) || (result == NULL)) {
484 #else
485   while (1) {
486     result = readdir(dp);
487     if (result == NULL) {
488 #endif
489       break;
490     }
491 
492     /* Exclude any name with ., .., not my_name or containing a space */
493     if (strcmp(result->d_name, ".") == 0 || strcmp(result->d_name, "..") == 0 ||
494         strncmp(result->d_name, my_name, my_name_len) != 0) {
495       Dmsg1(500, "Skipped: %s\n", result->d_name);
496       continue;
497     }
498 
499     /* Unlink files that match regex */
500     if (regexec(&preg1, result->d_name, 0, NULL, 0) == 0) {
501       PmStrcpy(cleanup, basename);
502       PmStrcat(cleanup, result->d_name);
503       Dmsg1(500, "Unlink: %s\n", cleanup);
504       SecureErase(NULL, cleanup);
505     }
506   }
507 #ifdef USE_READDIR_R
508   free(entry);
509 #endif
510   closedir(dp);
511 
512 get_out1:
513   regfree(&preg1);
514 get_out2:
515   FreePoolMemory(cleanup);
516   FreePoolMemory(basename);
517 }
518 
519 
520 /**
521  * Here we attempt to init and open each device. This is done once at startup in
522  * a separate thread.
523  */
524 extern "C" void* device_initialization(void* arg)
525 {
526   DeviceResource* device;
527   DeviceControlRecord* dcr;
528   JobControlRecord* jcr;
529   Device* dev;
530   int errstat;
531 
532   LockRes(my_config);
533 
534   pthread_detach(pthread_self());
535   jcr = NewStoredJcr();
536   NewPlugins(jcr); /* instantiate plugins */
537   jcr->setJobType(JT_SYSTEM);
538 
539   /*
540    * Initialize job start condition variable
541    */
542   errstat = pthread_cond_init(&jcr->impl->job_start_wait, NULL);
543   if (errstat != 0) {
544     BErrNo be;
545     Jmsg1(jcr, M_ABORT, 0,
546           _("Unable to init job start cond variable: ERR=%s\n"),
547           be.bstrerror(errstat));
548   }
549 
550   /*
551    * Initialize job end condition variable
552    */
553   errstat = pthread_cond_init(&jcr->impl->job_end_wait, NULL);
554   if (errstat != 0) {
555     BErrNo be;
556     Jmsg1(jcr, M_ABORT, 0,
557           _("Unable to init job endstart cond variable: ERR=%s\n"),
558           be.bstrerror(errstat));
559   }
560 
561   foreach_res (device, R_DEVICE) {
562     Dmsg1(90, "calling InitDev %s\n", device->device_name);
563     dev = InitDev(NULL, device);
564     Dmsg1(10, "SD init done %s\n", device->device_name);
565     if (!dev) {
566       Jmsg1(NULL, M_ERROR, 0, _("Could not initialize %s\n"),
567             device->device_name);
568       continue;
569     }
570 
571     dcr = new StorageDaemonDeviceControlRecord;
572     jcr->impl->dcr = dcr;
573     SetupNewDcrDevice(jcr, dcr, dev, NULL);
574     jcr->impl->dcr->SetWillWrite();
575     GeneratePluginEvent(jcr, bsdEventDeviceInit, dcr);
576     if (dev->IsAutochanger()) {
577       /*
578        * If autochanger set slot in dev structure
579        */
580       GetAutochangerLoadedSlot(dcr);
581     }
582 
583     if (BitIsSet(CAP_ALWAYSOPEN, device->cap_bits)) {
584       Dmsg1(20, "calling FirstOpenDevice %s\n", dev->print_name());
585       if (!FirstOpenDevice(dcr)) {
586         Jmsg1(NULL, M_ERROR, 0, _("Could not open device %s\n"),
587               dev->print_name());
588         Dmsg1(20, "Could not open device %s\n", dev->print_name());
589         FreeDeviceControlRecord(dcr);
590         jcr->impl->dcr = NULL;
591         continue;
592       }
593     }
594 
595     if (BitIsSet(CAP_AUTOMOUNT, device->cap_bits) && dev->IsOpen()) {
596       switch (ReadDevVolumeLabel(dcr)) {
597         case VOL_OK:
598           memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo));
599           VolumeUnused(dcr); /* mark volume "released" */
600           break;
601         default:
602           Jmsg1(NULL, M_WARNING, 0, _("Could not mount device %s\n"),
603                 dev->print_name());
604           break;
605       }
606     }
607     FreeDeviceControlRecord(dcr);
608     jcr->impl->dcr = NULL;
609   }
610   FreeJcr(jcr);
611   init_done = true;
612   UnlockRes(my_config);
613   return NULL;
614 }
615 
616 /**
617  * Clean up and then exit
618  */
619 namespace storagedaemon {
620 
621 #if !defined(HAVE_WIN32)
622 static
623 #endif
624     void
625     TerminateStored(int sig)
626 {
627   static bool in_here = false;
628   DeviceResource* device;
629   JobControlRecord* jcr;
630 
631   if (in_here) {       /* prevent loops */
632     Bmicrosleep(2, 0); /* yield */
633     exit(1);
634   }
635   in_here = true;
636   debug_level = 0; /* turn off any debug */
637   StopStatisticsThread();
638 #if HAVE_NDMP
639   if (me->ndmp_enable) { StopNdmpThreadServer(); }
640 #endif
641   StopSocketServer();
642 
643   StopWatchdog();
644 
645   if (sig == SIGTERM) { /* normal shutdown request? */
646     /*
647      * This is a normal shutdown request. We wiffle through
648      *   all open jobs canceling them and trying to wake
649      *   them up so that they will report back the correct
650      *   volume status.
651      */
652     foreach_jcr (jcr) {
653       BareosSocket* fd;
654       if (jcr->JobId == 0) { continue; /* ignore console */ }
655       jcr->setJobStatus(JS_Canceled);
656       fd = jcr->file_bsock;
657       if (fd) {
658         fd->SetTimedOut();
659         jcr->MyThreadSendSignal(TIMEOUT_SIGNAL);
660         Dmsg1(100, "term_stored killing JobId=%d\n", jcr->JobId);
661         /* ***FIXME*** wiffle through all dcrs */
662         if (jcr->impl->dcr && jcr->impl->dcr->dev &&
663             jcr->impl->dcr->dev->blocked()) {
664           pthread_cond_broadcast(&jcr->impl->dcr->dev->wait_next_vol);
665           Dmsg1(100, "JobId=%u broadcast wait_device_release\n",
666                 (uint32_t)jcr->JobId);
667           ReleaseDeviceCond();
668         }
669         if (jcr->impl->read_dcr && jcr->impl->read_dcr->dev &&
670             jcr->impl->read_dcr->dev->blocked()) {
671           pthread_cond_broadcast(&jcr->impl->read_dcr->dev->wait_next_vol);
672           Dmsg1(100, "JobId=%u broadcast wait_device_release\n",
673                 (uint32_t)jcr->JobId);
674           ReleaseDeviceCond();
675         }
676         Bmicrosleep(0, 50000);
677       }
678       FreeJcr(jcr);
679     }
680     Bmicrosleep(0, 500000); /* give them 1/2 sec to clean up */
681   }
682 
683   WriteStateFile(me->working_directory, "bareos-sd",
684                  GetFirstPortHostOrder(me->SDaddrs));
685   DeletePidFile(me->pid_directory, "bareos-sd",
686                 GetFirstPortHostOrder(me->SDaddrs));
687 
688   Dmsg1(200, "In TerminateStored() sig=%d\n", sig);
689 
690   UnloadSdPlugins();
691   FlushCryptoCache();
692   FreeVolumeLists();
693 
694   foreach_res (device, R_DEVICE) {
695     Dmsg1(10, "Term device %s\n", device->device_name);
696     if (device->dev) {
697       device->dev->ClearVolhdr();
698       device->dev->term();
699       device->dev = NULL;
700     } else {
701       Dmsg1(10, "No dev structure %s\n", device->device_name);
702     }
703   }
704 
705 #if defined(HAVE_DYNAMIC_SD_BACKENDS)
706   DevFlushBackends();
707 #endif
708 
709   if (configfile) {
710     free(configfile);
711     configfile = NULL;
712   }
713   if (my_config) {
714     delete my_config;
715     my_config = NULL;
716   }
717 
718   if (debug_level > 10) { PrintMemoryPoolStats(); }
719   TermMsg();
720   CleanupCrypto();
721   TermReservationsLock();
722   CloseMemoryPool();
723 
724   exit(sig);
725 }
726 
727 } /* namespace storagedaemon */
728