1 /*
2    BAREOS® - Backup Archiving REcovery Open Sourced
3 
4    Copyright (C) 2000-2011 Free Software Foundation Europe e.V.
5    Copyright (C) 2011-2012 Planets Communications B.V.
6    Copyright (C) 2013-2019 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, October MM
25  */
26 /**
27  * @file
28  * This file handles accepting Director Commands
29  */
30 
31 #include "include/bareos.h"
32 #include "filed/filed.h"
33 #include "filed/filed_globals.h"
34 #include "include/ch.h"
35 #include "filed/authenticate.h"
36 #include "filed/dir_cmd.h"
37 #include "filed/estimate.h"
38 #include "filed/evaluate_job_command.h"
39 #include "filed/heartbeat.h"
40 #include "filed/fileset.h"
41 #include "filed/jcr_private.h"
42 #include "filed/socket_server.h"
43 #include "filed/restore.h"
44 #include "filed/verify.h"
45 #include "findlib/enable_priv.h"
46 #include "findlib/shadowing.h"
47 #include "include/make_unique.h"
48 #include "lib/berrno.h"
49 #include "lib/bget_msg.h"
50 #include "lib/bnet.h"
51 #include "lib/edit.h"
52 #include "lib/path_list.h"
53 #include "lib/qualified_resource_name_type_converter.h"
54 #include "lib/thread_specific_data.h"
55 #include "lib/tls_conf.h"
56 #include "lib/parse_conf.h"
57 #include "lib/bsock_tcp.h"
58 #include "lib/bnet_network_dump.h"
59 #include "lib/watchdog.h"
60 #include "lib/util.h"
61 
62 #if defined(WIN32_VSS)
63 #include "win32/findlib/win32.h"
64 #pragma GCC diagnostic push
65 #pragma GCC diagnostic ignored "-Wunknown-pragmas"
66 #include "vss.h"
67 #pragma GCC diagnostic pop
68 #endif
69 
70 namespace filedaemon {
71 
72 extern bool backup_only_mode;
73 extern bool restore_only_mode;
74 
75 /**
76  * As Windows saves ACLs as part of the standard backup stream
77  * we just pretend here that is has implicit acl support.
78  */
79 #if defined(HAVE_ACL) || defined(HAVE_WIN32)
80 const bool have_acl = true;
81 #else
82 const bool have_acl = false;
83 #endif
84 
85 #if defined(HAVE_XATTR)
86 const bool have_xattr = true;
87 #else
88 const bool have_xattr = false;
89 #endif
90 
91 const bool have_encryption = true;
92 
93 /* Global variables to handle Client Initiated Connections */
94 static bool quit_client_initiate_connection = false;
95 static alist* client_initiated_connection_threads = nullptr;
96 
97 /* Imported functions */
98 extern bool AccurateCmd(JobControlRecord* jcr);
99 extern bool StatusCmd(JobControlRecord* jcr);
100 extern bool QstatusCmd(JobControlRecord* jcr);
101 extern "C" char* job_code_callback_filed(JobControlRecord* jcr,
102                                          const char* param);
103 
104 /* Forward referenced functions */
105 static bool BackupCmd(JobControlRecord* jcr);
106 static bool BootstrapCmd(JobControlRecord* jcr);
107 static bool CancelCmd(JobControlRecord* jcr);
108 static bool EndRestoreCmd(JobControlRecord* jcr);
109 static bool EstimateCmd(JobControlRecord* jcr);
110 #ifdef DEVELOPER
111 static bool exit_cmd(JobControlRecord* jcr);
112 #endif
113 static bool FilesetCmd(JobControlRecord* jcr);
114 static bool job_cmd(JobControlRecord* jcr);
115 static bool LevelCmd(JobControlRecord* jcr);
116 static bool PluginoptionsCmd(JobControlRecord* jcr);
117 static bool RunafterCmd(JobControlRecord* jcr);
118 static bool RunbeforenowCmd(JobControlRecord* jcr);
119 static bool RunbeforeCmd(JobControlRecord* jcr);
120 static bool RunscriptCmd(JobControlRecord* jcr);
121 static bool ResolveCmd(JobControlRecord* jcr);
122 static bool RestoreObjectCmd(JobControlRecord* jcr);
123 static bool RestoreCmd(JobControlRecord* jcr);
124 static bool SessionCmd(JobControlRecord* jcr);
125 static bool SecureerasereqCmd(JobControlRecord* jcr);
126 static bool SetauthorizationCmd(JobControlRecord* jcr);
127 static bool SetbandwidthCmd(JobControlRecord* jcr);
128 static bool SetdebugCmd(JobControlRecord* jcr);
129 static bool StorageCmd(JobControlRecord* jcr);
130 static bool VerifyCmd(JobControlRecord* jcr);
131 
132 static BareosSocket* connect_to_director(JobControlRecord* jcr,
133                                          DirectorResource* dir_res,
134                                          bool verbose);
135 static bool response(JobControlRecord* jcr,
136                      BareosSocket* sd,
137                      char* resp,
138                      const char* cmd);
139 static void FiledFreeJcr(JobControlRecord* jcr);
140 static bool OpenSdReadSession(JobControlRecord* jcr);
141 static void SetStorageAuthKeyAndTlsPolicy(JobControlRecord* jcr,
142                                           char* key,
143                                           TlsPolicy policy);
144 
145 /* Exported functions */
146 
147 struct s_cmds {
148   const char* cmd;
149   bool (*func)(JobControlRecord*);
150   bool monitoraccess; /* specify if monitors have access to this function */
151 };
152 
153 /**
154  * The following are the recognized commands from the Director.
155  *
156  * Keywords are sorted first longest match when the keywords start with the same
157  * string.
158  */
159 static struct s_cmds cmds[] = {
160     {"accurate", AccurateCmd, false},
161     {"backup", BackupCmd, false},
162     {"bootstrap", BootstrapCmd, false},
163     {"cancel", CancelCmd, false},
164     {"endrestore", EndRestoreCmd, false},
165     {"estimate", EstimateCmd, false},
166 #ifdef DEVELOPER
167     {"exit", exit_cmd, false},
168 #endif
169     {"fileset", FilesetCmd, false},
170     {"JobId=", job_cmd, false},
171     {"level = ", LevelCmd, false},
172     {"pluginoptions", PluginoptionsCmd, false},
173     {"RunAfterJob", RunafterCmd, false},
174     {"RunBeforeNow", RunbeforenowCmd, false},
175     {"RunBeforeJob", RunbeforeCmd, false},
176     {"Run", RunscriptCmd, false},
177     {"restoreobject", RestoreObjectCmd, false},
178     {"restore ", RestoreCmd, false},
179     {"resolve ", ResolveCmd, false},
180     {"getSecureEraseCmd", SecureerasereqCmd, false},
181     {"session", SessionCmd, false},
182     {"setauthorization", SetauthorizationCmd, false},
183     {"setbandwidth=", SetbandwidthCmd, false},
184     {"setdebug=", SetdebugCmd, false},
185     {"status", StatusCmd, true},
186     {".status", QstatusCmd, true},
187     {"storage ", StorageCmd, false},
188     {"verify", VerifyCmd, false},
189     {nullptr, nullptr, false} /* list terminator */
190 };
191 
192 /**
193  * Commands send to director
194  */
195 static char hello_client[] = "Hello Client %s FdProtocolVersion=%d calling\n";
196 
197 /**
198  * Responses received from the director
199  */
200 static const char OKversion[] = "1000 OK: %s Version: %s (%u %s %u)";
201 
202 /**
203  * Commands received from director that need scanning
204  */
205 static char setauthorizationcmd[] = "setauthorization Authorization=%100s";
206 static char setbandwidthcmd[] = "setbandwidth=%lld Job=%127s";
207 static char setdebugv0cmd[] = "setdebug=%d trace=%d";
208 static char setdebugv1cmd[] = "setdebug=%d trace=%d hangup=%d";
209 static char setdebugv2cmd[] = "setdebug=%d trace=%d hangup=%d timestamp=%d";
210 static char storaddrv0cmd[] = "storage address=%s port=%d ssl=%d";
211 static char storaddrv1cmd[] =
212     "storage address=%s port=%d ssl=%d Authorization=%100s";
213 static char sessioncmd[] = "session %127s %ld %ld %ld %ld %ld %ld\n";
214 static char restorecmd[] = "restore replace=%c prelinks=%d where=%s\n";
215 static char restorecmd1[] = "restore replace=%c prelinks=%d where=\n";
216 static char restorecmdR[] = "restore replace=%c prelinks=%d regexwhere=%s\n";
217 static char restoreobjcmd[] = "restoreobject JobId=%u %d,%d,%d,%d,%d,%d,%s";
218 static char restoreobjcmd1[] = "restoreobject JobId=%u %d,%d,%d,%d,%d,%d\n";
219 static char endrestoreobjectcmd[] = "restoreobject end\n";
220 static char pluginoptionscmd[] = "pluginoptions %s";
221 static char verifycmd[] = "verify level=%30s";
222 static char Estimatecmd[] = "estimate listing=%d";
223 static char runbeforecmd[] = "RunBeforeJob %s";
224 static char runaftercmd[] = "RunAfterJob %s";
225 static char runscriptcmd[] =
226     "Run OnSuccess=%d OnFailure=%d AbortOnError=%d When=%d Command=%s";
227 static char resolvecmd[] = "resolve %s";
228 
229 /**
230  * Responses sent to Director
231  */
232 static char errmsg[] = "2999 Invalid command\n";
233 static char invalid_cmd[] =
234     "2997 Invalid command for a Director with Monitor directive enabled.\n";
235 static char OkAuthorization[] = "2000 OK Authorization\n";
236 static char OKBandwidth[] = "2000 OK Bandwidth\n";
237 static char OKinc[] = "2000 OK include\n";
238 static char OKest[] = "2000 OK estimate files=%s bytes=%s\n";
239 static char OKlevel[] = "2000 OK level\n";
240 static char OKbackup[] = "2000 OK backup\n";
241 static char OKbootstrap[] = "2000 OK bootstrap\n";
242 static char OKverify[] = "2000 OK verify\n";
243 static char OKrestore[] = "2000 OK restore\n";
244 static char OKsecureerase[] = "2000 OK FDSecureEraseCmd %s\n";
245 static char OKsession[] = "2000 OK session\n";
246 static char OKstore[] = "2000 OK storage\n";
247 static char OKstoreend[] = "2000 OK storage end\n";
248 static char OKjob[] =
249     "2000 OK Job %s (%s) %s,%s,%s";
250 static char OKsetdebugv0[] =
251     "2000 OK setdebug=%d trace=%d hangup=%d tracefile=%s\n";
252 static char OKsetdebugv1[] =
253     "2000 OK setdebug=%d trace=%d hangup=%d timestamp=%d tracefile=%s\n";
254 static char BADjob[] = "2901 Bad Job\n";
255 static char EndJob[] =
256     "2800 End Job TermCode=%d JobFiles=%u ReadBytes=%s"
257     " JobBytes=%s Errors=%u VSS=%d Encrypt=%d\n";
258 static char OKRunBefore[] = "2000 OK RunBefore\n";
259 static char OKRunBeforeNow[] = "2000 OK RunBeforeNow\n";
260 static char OKRunAfter[] = "2000 OK RunAfter\n";
261 static char OKRunScript[] = "2000 OK RunScript\n";
262 static char BadRunBeforeJob[] = "2905 Bad RunBeforeJob command.\n";
263 static char FailedRunScript[] = "2905 Failed RunScript\n";
264 static char BadRunAfterJob[] = "2905 Bad RunAfterJob command.\n";
265 static char BADcmd[] = "2902 Bad %s\n";
266 static char OKRestoreObject[] = "2000 OK ObjectRestored\n";
267 static char OKPluginOptions[] = "2000 OK PluginOptions\n";
268 static char BadPluginOptions[] = "2905 Bad PluginOptions command.\n";
269 
270 /**
271  * Responses received from Storage Daemon
272  */
273 static char OK_end[] = "3000 OK end\n";
274 static char OK_close[] = "3000 OK close Status = %d\n";
275 static char OK_open[] = "3000 OK open ticket = %d\n";
276 static char OK_data[] = "3000 OK data\n";
277 static char OK_append[] = "3000 OK append data\n";
278 
279 /**
280  * Commands sent to Storage Daemon
281  */
282 static char append_open[] = "append open session\n";
283 static char append_data[] = "append data %d\n";
284 static char append_end[] = "append end session %d\n";
285 static char append_close[] = "append close session %d\n";
286 static char read_open[] = "read open session = %s %ld %ld %ld %ld %ld %ld\n";
287 static char read_data[] = "read data %d\n";
288 static char read_close[] = "read close session %d\n";
289 
290 /**
291  * See if we are allowed to execute the command issued.
292  */
ValidateCommand(JobControlRecord * jcr,const char * cmd,alist * allowed_job_cmds)293 static bool ValidateCommand(JobControlRecord* jcr,
294                             const char* cmd,
295                             alist* allowed_job_cmds)
296 {
297   char* allowed_job_cmd = nullptr;
298   bool allowed = false;
299 
300   /*
301    * If there is no explicit list of allowed cmds allow all cmds.
302    */
303   if (!allowed_job_cmds) { return true; }
304 
305   foreach_alist (allowed_job_cmd, allowed_job_cmds) {
306     if (Bstrcasecmp(cmd, allowed_job_cmd)) {
307       allowed = true;
308       break;
309     }
310   }
311 
312   if (!allowed) {
313     Jmsg(jcr, M_FATAL, 0,
314          _("Illegal \"%s\" command not allowed by Allowed Job Cmds setting of "
315            "this filed.\n"),
316          cmd);
317   }
318 
319   return allowed;
320 }
321 
CleanupFileset(JobControlRecord * jcr)322 static inline void CleanupFileset(JobControlRecord* jcr)
323 {
324   findFILESET* fileset;
325   findIncludeExcludeItem* incexe;
326   findFOPTS* fo;
327 
328   fileset = jcr->impl->ff->fileset;
329   if (fileset) {
330     /*
331      * Delete FileSet Include lists
332      */
333     for (int i = 0; i < fileset->include_list.size(); i++) {
334       incexe = (findIncludeExcludeItem*)fileset->include_list.get(i);
335       for (int j = 0; j < incexe->opts_list.size(); j++) {
336         fo = (findFOPTS*)incexe->opts_list.get(j);
337         if (fo->plugin) { free(fo->plugin); }
338         for (int k = 0; k < fo->regex.size(); k++) {
339           regfree((regex_t*)fo->regex.get(k));
340         }
341         for (int k = 0; k < fo->regexdir.size(); k++) {
342           regfree((regex_t*)fo->regexdir.get(k));
343         }
344         for (int k = 0; k < fo->regexfile.size(); k++) {
345           regfree((regex_t*)fo->regexfile.get(k));
346         }
347         if (fo->size_match) { free(fo->size_match); }
348         fo->regex.destroy();
349         fo->regexdir.destroy();
350         fo->regexfile.destroy();
351         fo->wild.destroy();
352         fo->wilddir.destroy();
353         fo->wildfile.destroy();
354         fo->wildbase.destroy();
355         fo->base.destroy();
356         fo->fstype.destroy();
357         fo->Drivetype.destroy();
358       }
359       incexe->opts_list.destroy();
360       incexe->name_list.destroy();
361       incexe->plugin_list.destroy();
362       incexe->ignoredir.destroy();
363     }
364     fileset->include_list.destroy();
365 
366     /*
367      * Delete FileSet Exclude lists
368      */
369     for (int i = 0; i < fileset->exclude_list.size(); i++) {
370       incexe = (findIncludeExcludeItem*)fileset->exclude_list.get(i);
371       for (int j = 0; j < incexe->opts_list.size(); j++) {
372         fo = (findFOPTS*)incexe->opts_list.get(j);
373         if (fo->size_match) { free(fo->size_match); }
374         fo->regex.destroy();
375         fo->regexdir.destroy();
376         fo->regexfile.destroy();
377         fo->wild.destroy();
378         fo->wilddir.destroy();
379         fo->wildfile.destroy();
380         fo->wildbase.destroy();
381         fo->base.destroy();
382         fo->fstype.destroy();
383         fo->Drivetype.destroy();
384       }
385       incexe->opts_list.destroy();
386       incexe->name_list.destroy();
387       incexe->plugin_list.destroy();
388       incexe->ignoredir.destroy();
389     }
390     fileset->exclude_list.destroy();
391     free(fileset);
392   }
393   jcr->impl->ff->fileset = nullptr;
394 }
395 
AreMaxConcurrentJobsExceeded()396 static inline bool AreMaxConcurrentJobsExceeded()
397 {
398   JobControlRecord* jcr;
399   unsigned int cnt = 0;
400 
401   foreach_jcr (jcr) {
402     cnt++;
403   }
404   endeach_jcr(jcr);
405 
406   return (cnt >= me->MaxConcurrentJobs) ? true : false;
407 }
408 
NewFiledJcr()409 static JobControlRecord* NewFiledJcr()
410 {
411   JobControlRecord* jcr = new_jcr(FiledFreeJcr);
412   jcr->impl = new JobControlRecordPrivate;
413   return jcr;
414 }
415 
create_new_director_session(BareosSocket * dir)416 JobControlRecord* create_new_director_session(BareosSocket* dir)
417 {
418   const char jobname[12] = "*Director*";
419 
420   JobControlRecord* jcr{NewFiledJcr()};
421   jcr->dir_bsock = dir;
422   jcr->impl->ff = init_find_files();
423   jcr->start_time = time(nullptr);
424   jcr->impl->RunScripts = new alist(10, not_owned_by_alist);
425   jcr->impl->last_fname = GetPoolMemory(PM_FNAME);
426   jcr->impl->last_fname[0] = 0;
427   jcr->client_name = GetMemory(strlen(my_name) + 1);
428   PmStrcpy(jcr->client_name, my_name);
429   bstrncpy(jcr->Job, jobname, sizeof(jobname)); /* dummy */
430   jcr->impl->crypto.pki_sign = me->pki_sign;
431   jcr->impl->crypto.pki_encrypt = me->pki_encrypt;
432   jcr->impl->crypto.pki_keypair = me->pki_keypair;
433   jcr->impl->crypto.pki_signers = me->pki_signers;
434   jcr->impl->crypto.pki_recipients = me->pki_recipients;
435   if (dir) { dir->SetJcr(jcr); }
436   SetJcrInThreadSpecificData(jcr);
437 
438   EnableBackupPrivileges(nullptr, 1 /* ignore_errors */);
439 
440   return jcr;
441 }
442 
process_director_commands(void * p_jcr)443 void* process_director_commands(void* p_jcr)
444 {
445   JobControlRecord* jcr = (JobControlRecord*)p_jcr;
446   return process_director_commands(jcr, jcr->dir_bsock);
447 }
448 
process_director_commands(JobControlRecord * jcr,BareosSocket * dir)449 void* process_director_commands(JobControlRecord* jcr, BareosSocket* dir)
450 {
451   bool found;
452   bool quit = false;
453 
454   /**********FIXME******* add command handler error code */
455 
456   while (jcr->authenticated && (!quit)) {
457     /*
458      * Read command
459      */
460     if (dir->recv() < 0) { break; /* connection terminated */ }
461 
462     dir->msg[dir->message_length] = 0;
463     Dmsg1(100, "<dird: %s\n", dir->msg);
464     found = false;
465     for (int i = 0; cmds[i].cmd; i++) {
466       if (bstrncmp(cmds[i].cmd, dir->msg, strlen(cmds[i].cmd))) {
467         found = true; /* indicate command found */
468         if ((!cmds[i].monitoraccess) && (jcr->impl->director->monitor)) {
469           Dmsg1(100, "Command \"%s\" is invalid.\n", cmds[i].cmd);
470           dir->fsend(invalid_cmd);
471           dir->signal(BNET_EOD);
472           break;
473         }
474         Dmsg1(100, "Executing %s command.\n", cmds[i].cmd);
475         if (!cmds[i].func(jcr)) { /* do command */
476           quit = true;            /* error or fully terminated, get out */
477           Dmsg1(100, "Quit command loop. Canceled=%d\n", JobCanceled(jcr));
478         }
479         break;
480       }
481     }
482     if (!found) { /* command not found */
483       dir->fsend(errmsg);
484       quit = true;
485       break;
486     }
487   }
488 
489   /*
490    * Inform Storage daemon that we are done
491    */
492   if (jcr->store_bsock) { jcr->store_bsock->signal(BNET_TERMINATE); }
493 
494   /*
495    * Run the after job
496    */
497   if (jcr->impl->RunScripts) {
498     RunScripts(jcr, jcr->impl->RunScripts, "ClientAfterJob",
499                (jcr->impl->director && jcr->impl->director->allowed_script_dirs)
500                    ? jcr->impl->director->allowed_script_dirs
501                    : me->allowed_script_dirs);
502   }
503 
504   if (jcr->JobId) { /* send EndJob if running a job */
505     char ed1[50], ed2[50];
506     /*
507      * Send termination status back to Dir
508      */
509     dir->fsend(EndJob, jcr->JobStatus, jcr->JobFiles,
510                edit_uint64(jcr->ReadBytes, ed1),
511                edit_uint64(jcr->JobBytes, ed2), jcr->JobErrors,
512                jcr->impl->enable_vss, jcr->impl->crypto.pki_encrypt);
513     Dmsg1(110, "End FD msg: %s\n", dir->msg);
514   }
515 
516   GeneratePluginEvent(jcr, bEventJobEnd);
517 
518   DequeueMessages(jcr); /* send any queued messages */
519 
520   /*
521    * Inform Director that we are done
522    */
523   dir->signal(BNET_TERMINATE);
524 
525   FreePlugins(jcr); /* release instantiated plugins */
526   FreeAndNullPoolMemory(jcr->impl->job_metadata);
527 
528   /*
529    * Clean up fileset
530    */
531   CleanupFileset(jcr);
532 
533   FreeJcr(jcr); /* destroy JobControlRecord record */
534   Dmsg0(100, "Done with FreeJcr\n");
535   GarbageCollectMemoryPool();
536 
537 #ifdef HAVE_WIN32
538   AllowOsSuspensions();
539 #endif
540 
541   return nullptr;
542 }
543 
544 /**
545  * Create a new thread to handle director connection.
546  */
StartProcessDirectorCommands(JobControlRecord * jcr)547 static bool StartProcessDirectorCommands(JobControlRecord* jcr)
548 {
549   int result = 0;
550   pthread_t thread;
551 
552   if ((result = pthread_create(&thread, nullptr, process_director_commands,
553                                (void*)jcr)) != 0) {
554     BErrNo be;
555     Emsg1(M_ABORT, 0, _("Cannot create Director connect thread: %s\n"),
556           be.bstrerror(result));
557   }
558 
559   return (result == 0);
560 }
561 
562 /**
563  * Connection request from an director.
564  *
565  * Accept commands one at a time from the Director and execute them.
566  *
567  * Concerning ClientRunBefore/After, the sequence of events is rather critical.
568  * If they are not done in the right order one can easily get FD->SD timeouts
569  * if the script runs a long time.
570  *
571  * The current sequence of events is:
572  *  1. Dir starts job with FD
573  *  2. Dir connects to SD
574  *  3. Dir connects to FD
575  *  4. FD connects to SD
576  *  5. FD gets/runs ClientRunBeforeJob and sends ClientRunAfterJob
577  *  6. Dir sends include/exclude
578  *  7. FD sends data to SD
579  *  8. SD/FD disconnects while SD despools data and attributes (optional)
580  *  9. FD runs ClientRunAfterJob
581  */
handle_director_connection(BareosSocket * dir)582 void* handle_director_connection(BareosSocket* dir)
583 {
584   JobControlRecord* jcr;
585 
586 #ifdef HAVE_WIN32
587   PreventOsSuspensions();
588 #endif
589 
590   if (AreMaxConcurrentJobsExceeded()) {
591     Emsg0(
592         M_ERROR, 0,
593         _("Number of Jobs exhausted, please increase MaximumConcurrentJobs\n"));
594     return nullptr;
595   }
596 
597   jcr = create_new_director_session(dir);
598 
599   Dmsg0(120, "Calling Authenticate\n");
600   if (AuthenticateDirector(jcr)) { Dmsg0(120, "OK Authenticate\n"); }
601 
602   return process_director_commands(jcr, dir);
603 }
604 
ParseOkVersion(const char * string)605 static bool ParseOkVersion(const char* string)
606 {
607   char name[MAX_NAME_LENGTH];
608   char version[MAX_NAME_LENGTH];
609   unsigned int day = 0;
610   char month[100];
611   unsigned int year = 0;
612   int number = 0;
613 
614   number = sscanf(string, OKversion, &name, &version, &day, &month, &year);
615   Dmsg2(120, "OK message: %s, Version: %s\n", name, version);
616   return (number == 5);
617 }
618 
handle_connection_to_director(void * director_resource)619 static void* handle_connection_to_director(void* director_resource)
620 {
621   DirectorResource* dir_res = (DirectorResource*)director_resource;
622   BareosSocket* dir_bsock = nullptr;
623   JobControlRecord* jcr = nullptr;
624   int data_available = 0;
625   int retry_period = 60;
626   const int timeout_data = 60;
627 
628   while (!quit_client_initiate_connection) {
629     if (jcr) {
630       FreeJcr(jcr);
631       jcr = nullptr;
632     }
633 
634     jcr = create_new_director_session(nullptr);
635     dir_bsock = connect_to_director(jcr, dir_res, true);
636     if (!dir_bsock) {
637       Emsg2(M_ERROR, 0, "Failed to connect to Director \"%s\". Retry in %ds.\n",
638             dir_res->resource_name_, retry_period);
639       sleep(retry_period);
640     } else {
641       Dmsg1(120, "Connected to \"%s\".\n", dir_res->resource_name_);
642 
643       /*
644        * Returns: 1 if data available, 0 if timeout, -1 if error
645        */
646       data_available = 0;
647       while ((data_available == 0) && (!quit_client_initiate_connection)) {
648         Dmsg2(120, "Waiting for data from Director \"%s\" (timeout: %ds)\n",
649               dir_res->resource_name_, timeout_data);
650         data_available = dir_bsock->WaitDataIntr(timeout_data);
651       }
652       if (!quit_client_initiate_connection) {
653         if (data_available < 0) {
654           Emsg1(M_ABORT, 0,
655                 _("Failed while waiting for data from Director \"%s\"\n"),
656                 dir_res->resource_name_);
657         } else {
658           /*
659            * data is available
660            */
661           dir_bsock->SetJcr(jcr);
662           jcr->dir_bsock = dir_bsock;
663           if (StartProcessDirectorCommands(jcr)) {
664             /*
665              * jcr (and dir_bsock) are now used by another thread.
666              */
667             dir_bsock = nullptr;
668             jcr = nullptr;
669           }
670         }
671       }
672     }
673   }
674 
675   Dmsg1(100, "Exiting Client Initiated Connection thread for %s\n",
676         dir_res->resource_name_);
677   if (jcr) {
678     /*
679      * cleanup old data structures
680      */
681     FreeJcr(jcr);
682   }
683 
684   return nullptr;
685 }
686 
StartConnectToDirectorThreads()687 bool StartConnectToDirectorThreads()
688 {
689   bool result = false;
690   DirectorResource* dir_res = nullptr;
691   int pthread_create_result = 0;
692   if (!client_initiated_connection_threads) {
693     client_initiated_connection_threads = new alist();
694   }
695   pthread_t* thread;
696 
697   foreach_res (dir_res, R_DIRECTOR) {
698     if (dir_res->conn_from_fd_to_dir) {
699       if (!dir_res->address) {
700         Emsg1(M_ERROR, 0,
701               "Failed to connect to Director \"%s\". The address config "
702               "directive is missing.\n",
703               dir_res->resource_name_);
704       } else if (!dir_res->port) {
705         Emsg1(M_ERROR, 0,
706               "Failed to connect to Director \"%s\". The port config directive "
707               "is missing.\n",
708               dir_res->resource_name_);
709       } else {
710         Dmsg3(120, "Connecting to Director \"%s\", address %s:%d.\n",
711               dir_res->resource_name_, dir_res->address, dir_res->port);
712         thread = (pthread_t*)malloc(sizeof(pthread_t));
713         if ((pthread_create_result =
714                  pthread_create(thread, nullptr, handle_connection_to_director,
715                                 (void*)dir_res)) == 0) {
716           client_initiated_connection_threads->append(thread);
717         } else {
718           BErrNo be;
719           Emsg1(M_ABORT, 0, _("Cannot create Director connect thread: %s\n"),
720                 be.bstrerror(pthread_create_result));
721         }
722       }
723     }
724   }
725 
726   return result;
727 }
728 
StopConnectToDirectorThreads(bool wait)729 bool StopConnectToDirectorThreads(bool wait)
730 {
731   bool result = true;
732   pthread_t* thread = nullptr;
733   quit_client_initiate_connection = true;
734   if (client_initiated_connection_threads) {
735     while (!client_initiated_connection_threads->empty()) {
736       thread = (pthread_t*)client_initiated_connection_threads->remove(0);
737       if (thread) {
738         pthread_kill(*thread, TIMEOUT_SIGNAL);
739         if (wait) {
740           if (pthread_join(*thread, nullptr) != 0) { result = false; }
741         }
742         free(thread);
743       }
744     }
745     delete (client_initiated_connection_threads);
746   }
747   return result;
748 }
749 
750 /**
751  * Resolve a hostname
752  */
ResolveCmd(JobControlRecord * jcr)753 static bool ResolveCmd(JobControlRecord* jcr)
754 {
755   BareosSocket* dir = jcr->dir_bsock;
756   dlist* addr_list;
757   const char* errstr;
758   char addresses[2048];
759   char hostname[2048];
760 
761   sscanf(dir->msg, resolvecmd, &hostname);
762 
763   if ((addr_list = BnetHost2IpAddrs(hostname, 0, &errstr)) == nullptr) {
764     dir->fsend(_("%s: Failed to resolve %s\n"), my_name, hostname);
765     goto bail_out;
766   }
767 
768   dir->fsend(
769       _("%s resolves %s to %s\n"), my_name, hostname,
770       BuildAddressesString(addr_list, addresses, sizeof(addresses), false));
771   FreeAddresses(addr_list);
772 
773 bail_out:
774   dir->signal(BNET_EOD);
775   return true;
776 }
777 
SecureerasereqCmd(JobControlRecord * jcr)778 static bool SecureerasereqCmd(JobControlRecord* jcr)
779 {
780   const char* setting;
781   BareosSocket* dir = jcr->dir_bsock;
782 
783   setting = me->secure_erase_cmdline ? me->secure_erase_cmdline : "*None*";
784   Dmsg1(200, "Secure Erase Cmd Request: %s\n", setting);
785   return dir->fsend(OKsecureerase, setting);
786 }
787 
788 #ifdef DEVELOPER
exit_cmd(JobControlRecord * jcr)789 static bool exit_cmd(JobControlRecord* jcr)
790 {
791   jcr->dir_bsock->fsend("2000 exit OK\n");
792   // terminate_filed(0);
793   StopSocketServer();
794   return false;
795 }
796 #endif
797 
798 /**
799  * Cancel a Job
800  */
CancelCmd(JobControlRecord * jcr)801 static bool CancelCmd(JobControlRecord* jcr)
802 {
803   BareosSocket* dir = jcr->dir_bsock;
804   char Job[MAX_NAME_LENGTH];
805   JobControlRecord* cjcr;
806 
807   if (sscanf(dir->msg, "cancel Job=%127s", Job) == 1) {
808     if (!(cjcr = get_jcr_by_full_name(Job))) {
809       dir->fsend(_("2901 Job %s not found.\n"), Job);
810     } else {
811       GeneratePluginEvent(cjcr, bEventCancelCommand, nullptr);
812       cjcr->setJobStatus(JS_Canceled);
813       if (cjcr->store_bsock) {
814         cjcr->store_bsock->SetTimedOut();
815         cjcr->store_bsock->SetTerminated();
816       }
817       cjcr->MyThreadSendSignal(TIMEOUT_SIGNAL);
818       FreeJcr(cjcr);
819       dir->fsend(_("2001 Job %s marked to be canceled.\n"), Job);
820     }
821   } else {
822     dir->fsend(_("2902 Error scanning cancel command.\n"));
823   }
824   dir->signal(BNET_EOD);
825   return true;
826 }
827 
828 /**
829  * Set new authorization key as requested by the Director
830  */
SetauthorizationCmd(JobControlRecord * jcr)831 static bool SetauthorizationCmd(JobControlRecord* jcr)
832 {
833   BareosSocket* dir = jcr->dir_bsock;
834   PoolMem sd_auth_key(PM_MESSAGE);
835 
836   sd_auth_key.check_size(dir->message_length);
837   if (sscanf(dir->msg, setauthorizationcmd, sd_auth_key.c_str()) != 1) {
838     dir->fsend(BADcmd, "setauthorization");
839     return false;
840   }
841 
842   SetStorageAuthKeyAndTlsPolicy(jcr, sd_auth_key.c_str(), jcr->sd_tls_policy);
843   Dmsg2(120, "JobId=%d Auth=%s\n", jcr->JobId, jcr->sd_auth_key);
844 
845   return dir->fsend(OkAuthorization);
846 }
847 
848 /**
849  * Set bandwidth limit as requested by the Director
850  */
SetbandwidthCmd(JobControlRecord * jcr)851 static bool SetbandwidthCmd(JobControlRecord* jcr)
852 {
853   BareosSocket* dir = jcr->dir_bsock;
854   int64_t bw = 0;
855   JobControlRecord* cjcr;
856   char Job[MAX_NAME_LENGTH];
857 
858   *Job = 0;
859   if (sscanf(dir->msg, setbandwidthcmd, &bw, Job) != 2 || bw < 0) {
860     PmStrcpy(jcr->errmsg, dir->msg);
861     dir->fsend(_("2991 Bad setbandwidth command: %s\n"), jcr->errmsg);
862     return false;
863   }
864 
865   if (*Job) {
866     if (!(cjcr = get_jcr_by_full_name(Job))) {
867       dir->fsend(_("2901 Job %s not found.\n"), Job);
868     } else {
869       cjcr->max_bandwidth = bw;
870       if (cjcr->store_bsock) {
871         cjcr->store_bsock->SetBwlimit(bw);
872         if (me->allow_bw_bursting) { cjcr->store_bsock->SetBwlimitBursting(); }
873       }
874       FreeJcr(cjcr);
875     }
876   } else {                          /* No job requested, apply globally */
877     me->max_bandwidth_per_job = bw; /* Overwrite directive */
878   }
879 
880   return dir->fsend(OKBandwidth);
881 }
882 
883 /**
884  * Set debug level as requested by the Director
885  */
SetdebugCmd(JobControlRecord * jcr)886 static bool SetdebugCmd(JobControlRecord* jcr)
887 {
888   BareosSocket* dir = jcr->dir_bsock;
889   int32_t level, trace_flag, hangup_flag, timestamp_flag;
890   int scan;
891 
892   Dmsg1(50, "SetdebugCmd: %s", dir->msg);
893   scan = sscanf(dir->msg, setdebugv2cmd, &level, &trace_flag, &hangup_flag,
894                 &timestamp_flag);
895   if (scan != 4) {
896     scan = sscanf(dir->msg, setdebugv1cmd, &level, &trace_flag, &hangup_flag);
897   }
898   if (scan != 3 && scan != 4) {
899     scan = sscanf(dir->msg, setdebugv0cmd, &level, &trace_flag);
900     if (scan != 2) {
901       PmStrcpy(jcr->errmsg, dir->msg);
902       dir->fsend(_("2991 Bad setdebug command: %s\n"), jcr->errmsg);
903       return false;
904     } else {
905       hangup_flag = -1;
906     }
907   }
908 
909   PoolMem tracefilename(PM_FNAME);
910   Mmsg(tracefilename, "%s/%s.trace", TRACEFILEDIRECTORY, my_name);
911 
912   if (level >= 0) { debug_level = level; }
913 
914   SetTrace(trace_flag);
915   SetHangup(hangup_flag);
916   if (scan == 4) {
917     SetTimestamp(timestamp_flag);
918     Dmsg5(50, "level=%d trace=%d hangup=%d timestamp=%d tracefilename=%s\n",
919           level, GetTrace(), GetHangup(), GetTimestamp(),
920           tracefilename.c_str());
921     return dir->fsend(OKsetdebugv1, level, GetTrace(), GetHangup(),
922                       GetTimestamp(), tracefilename.c_str());
923   } else {
924     Dmsg4(50, "level=%d trace=%d hangup=%d tracefilename=%s\n", level,
925           GetTrace(), GetHangup(), tracefilename.c_str());
926     return dir->fsend(OKsetdebugv0, level, GetTrace(), GetHangup(),
927                       tracefilename.c_str());
928   }
929 }
930 
EstimateCmd(JobControlRecord * jcr)931 static bool EstimateCmd(JobControlRecord* jcr)
932 {
933   BareosSocket* dir = jcr->dir_bsock;
934   char ed1[50], ed2[50];
935 
936   /*
937    * See if we are allowed to run estimate cmds.
938    */
939   if (!ValidateCommand(
940           jcr, "estimate",
941           (jcr->impl->director && jcr->impl->director->allowed_job_cmds)
942               ? jcr->impl->director->allowed_job_cmds
943               : me->allowed_job_cmds)) {
944     dir->fsend(_("2992 Bad estimate command.\n"));
945     return 0;
946   }
947 
948   if (sscanf(dir->msg, Estimatecmd, &jcr->impl->listing) != 1) {
949     PmStrcpy(jcr->errmsg, dir->msg);
950     Jmsg(jcr, M_FATAL, 0, _("Bad estimate command: %s"), jcr->errmsg);
951     dir->fsend(_("2992 Bad estimate command.\n"));
952     return false;
953   }
954 
955   MakeEstimate(jcr);
956 
957   dir->fsend(OKest, edit_uint64_with_commas(jcr->impl->num_files_examined, ed1),
958              edit_uint64_with_commas(jcr->JobBytes, ed2));
959   dir->signal(BNET_EOD);
960 
961   return true;
962 }
963 
964 /**
965  * Get JobId and Storage Daemon Authorization key from Director
966  */
job_cmd(JobControlRecord * jcr)967 static bool job_cmd(JobControlRecord* jcr)
968 {
969   BareosSocket* dir = jcr->dir_bsock;
970 
971   JobCommand command(dir->msg);
972 
973   if (!command.EvaluationSuccesful()) {
974     PmStrcpy(jcr->errmsg, dir->msg);
975     Jmsg(jcr, M_FATAL, 0, _("Bad Job Command: %s"), jcr->errmsg);
976     dir->fsend(BADjob);
977     return false;
978   }
979 
980   jcr->JobId = command.job_id_;
981   strncpy(jcr->Job, command.job_, sizeof(jcr->Job));
982   jcr->VolSessionId = command.vol_session_id_;
983   jcr->VolSessionTime = command.vol_session_time_;
984 
985   TlsPolicy tls_policy =
986       command.protocol_version_ ==
987               JobCommand::ProtocolVersion::KVersionBefore_18_2
988           ? TlsPolicy::kBnetTlsNone
989           : command.tls_policy_;
990 
991   SetStorageAuthKeyAndTlsPolicy(jcr, command.sd_auth_key_, tls_policy);
992   Dmsg3(120, "JobId=%d Auth=%s TlsPolicy=%d\n", jcr->JobId, jcr->sd_auth_key,
993         tls_policy);
994   Mmsg(jcr->errmsg, "JobId=%d Job=%s", jcr->JobId, jcr->Job);
995   NewPlugins(jcr); /* instantiate plugins for this jcr */
996   GeneratePluginEvent(jcr, bEventJobStart, (void*)jcr->errmsg);
997 
998   const char* os_version;
999 #ifdef HAVE_WIN32
1000   os_version = win_os;
1001 #else
1002   os_version = HOST_OS;
1003 #endif
1004 
1005   return dir->fsend(OKjob, kBareosVersionStrings.Full,
1006                     kBareosVersionStrings.ShortDate, os_version, DISTNAME,
1007                     DISTVER);
1008 }
1009 
RunbeforeCmd(JobControlRecord * jcr)1010 static bool RunbeforeCmd(JobControlRecord* jcr)
1011 {
1012   bool ok;
1013   POOLMEM* cmd;
1014   RunScript* script;
1015   BareosSocket* dir = jcr->dir_bsock;
1016 
1017   if (!me->compatible) {
1018     dir->fsend(BadRunBeforeJob);
1019     return false;
1020   }
1021 
1022   Dmsg1(100, "RunbeforeCmd: %s", dir->msg);
1023   cmd = GetMemory(dir->message_length + 1);
1024   if (sscanf(dir->msg, runbeforecmd, cmd) != 1) {
1025     PmStrcpy(jcr->errmsg, dir->msg);
1026     Jmsg1(jcr, M_FATAL, 0, _("Bad RunBeforeJob command: %s\n"), jcr->errmsg);
1027     dir->fsend(BadRunBeforeJob);
1028     FreeMemory(cmd);
1029     return false;
1030   }
1031   UnbashSpaces(cmd);
1032 
1033   /*
1034    * Run the command now
1035    */
1036 
1037   Dmsg0(500, "runscript: creating new RunScript object\n");
1038   script = new RunScript;
1039   script->SetJobCodeCallback(job_code_callback_filed);
1040   script->SetCommand(cmd);
1041   script->when = SCRIPT_Before;
1042   FreeMemory(cmd);
1043 
1044   ok = script->Run(jcr, "ClientRunBeforeJob");
1045   FreeRunscript(script);
1046 
1047   if (ok) {
1048     dir->fsend(OKRunBefore);
1049     return true;
1050   } else {
1051     dir->fsend(BadRunBeforeJob);
1052     return false;
1053   }
1054 }
1055 
RunbeforenowCmd(JobControlRecord * jcr)1056 static bool RunbeforenowCmd(JobControlRecord* jcr)
1057 {
1058   BareosSocket* dir = jcr->dir_bsock;
1059 
1060   RunScripts(jcr, jcr->impl->RunScripts, "ClientBeforeJob",
1061              (jcr->impl->director && jcr->impl->director->allowed_script_dirs)
1062                  ? jcr->impl->director->allowed_script_dirs
1063                  : me->allowed_script_dirs);
1064 
1065   if (JobCanceled(jcr)) {
1066     dir->fsend(FailedRunScript);
1067     Dmsg0(100, "Back from RunScripts ClientBeforeJob now: FAILED\n");
1068     return false;
1069   } else {
1070     dir->fsend(OKRunBeforeNow);
1071     Dmsg0(100, "Back from RunScripts ClientBeforeJob now: OK\n");
1072     return true;
1073   }
1074 }
1075 
RunafterCmd(JobControlRecord * jcr)1076 static bool RunafterCmd(JobControlRecord* jcr)
1077 {
1078   BareosSocket* dir = jcr->dir_bsock;
1079   POOLMEM* cmd;
1080   RunScript* script;
1081 
1082   if (!me->compatible) {
1083     dir->fsend(BadRunAfterJob);
1084     return false;
1085   }
1086 
1087   Dmsg1(100, "RunafterCmd: %s", dir->msg);
1088   cmd = GetMemory(dir->message_length + 1);
1089   if (sscanf(dir->msg, runaftercmd, cmd) != 1) {
1090     PmStrcpy(jcr->errmsg, dir->msg);
1091     Jmsg1(jcr, M_FATAL, 0, _("Bad RunAfter command: %s\n"), jcr->errmsg);
1092     dir->fsend(BadRunAfterJob);
1093     FreeMemory(cmd);
1094     return false;
1095   }
1096   UnbashSpaces(cmd);
1097 
1098   Dmsg0(500, "runscript: creating new RunScript object\n");
1099   script = new RunScript;
1100   script->SetJobCodeCallback(job_code_callback_filed);
1101   script->SetCommand(cmd);
1102   script->on_success = true;
1103   script->on_failure = false;
1104   script->when = SCRIPT_After;
1105   FreeMemory(cmd);
1106 
1107   jcr->impl->RunScripts->append(script);
1108 
1109   return dir->fsend(OKRunAfter);
1110 }
1111 
RunscriptCmd(JobControlRecord * jcr)1112 static bool RunscriptCmd(JobControlRecord* jcr)
1113 {
1114   POOLMEM* msg;
1115   RunScript* cmd;
1116   BareosSocket* dir = jcr->dir_bsock;
1117   int on_success, on_failure, fail_on_error;
1118 
1119   /*
1120    * See if we are allowed to run runscript cmds.
1121    */
1122   if (!ValidateCommand(
1123           jcr, "runscript",
1124           (jcr->impl->director && jcr->impl->director->allowed_job_cmds)
1125               ? jcr->impl->director->allowed_job_cmds
1126               : me->allowed_job_cmds)) {
1127     dir->fsend(FailedRunScript);
1128     return 0;
1129   }
1130 
1131   msg = GetMemory(dir->message_length + 1);
1132   Dmsg0(500, "runscript: creating new RunScript object\n");
1133   cmd = new RunScript;
1134   cmd->SetJobCodeCallback(job_code_callback_filed);
1135 
1136   Dmsg1(100, "RunscriptCmd: '%s'\n", dir->msg);
1137 
1138   /*
1139    * Note, we cannot sscanf into bools
1140    */
1141   if (sscanf(dir->msg, runscriptcmd, &on_success, &on_failure, &fail_on_error,
1142              &cmd->when, msg) != 5) {
1143     PmStrcpy(jcr->errmsg, dir->msg);
1144     Jmsg1(jcr, M_FATAL, 0, _("Bad RunScript command: %s\n"), jcr->errmsg);
1145     dir->fsend(FailedRunScript);
1146     FreeRunscript(cmd);
1147     FreeMemory(msg);
1148     return false;
1149   }
1150 
1151   cmd->on_success = on_success;
1152   cmd->on_failure = on_failure;
1153   cmd->fail_on_error = fail_on_error;
1154   UnbashSpaces(msg);
1155 
1156   cmd->SetCommand(msg);
1157   cmd->Debug();
1158   jcr->impl->RunScripts->append(cmd);
1159 
1160   FreePoolMemory(msg);
1161 
1162   return dir->fsend(OKRunScript);
1163 }
1164 
1165 /**
1166  * This passes plugin specific options.
1167  */
PluginoptionsCmd(JobControlRecord * jcr)1168 static bool PluginoptionsCmd(JobControlRecord* jcr)
1169 {
1170   BareosSocket* dir = jcr->dir_bsock;
1171   POOLMEM* msg;
1172 
1173   msg = GetMemory(dir->message_length + 1);
1174   if (sscanf(dir->msg, pluginoptionscmd, msg) != 1) {
1175     PmStrcpy(jcr->errmsg, dir->msg);
1176     Jmsg1(jcr, M_FATAL, 0, _("Bad Plugin Options command: %s\n"), jcr->errmsg);
1177     dir->fsend(BadPluginOptions);
1178     FreeMemory(msg);
1179     return false;
1180   }
1181 
1182   UnbashSpaces(msg);
1183   GeneratePluginEvent(jcr, bEventNewPluginOptions, (void*)msg);
1184   FreeMemory(msg);
1185 
1186   return dir->fsend(OKPluginOptions);
1187 }
1188 
1189 /**
1190  * This reads data sent from the Director from the
1191  * RestoreObject table that allows us to get objects
1192  * that were backed up (VSS .xml data) and are needed
1193  * before starting the restore.
1194  */
RestoreObjectCmd(JobControlRecord * jcr)1195 static bool RestoreObjectCmd(JobControlRecord* jcr)
1196 {
1197   BareosSocket* dir = jcr->dir_bsock;
1198   int32_t FileIndex;
1199   restore_object_pkt rop;
1200 
1201   memset(&rop, 0, sizeof(rop));
1202   rop.pkt_size = sizeof(rop);
1203   rop.pkt_end = sizeof(rop);
1204 
1205   Dmsg1(100, "Enter restoreobject_cmd: %s", dir->msg);
1206   if (bstrcmp(dir->msg, endrestoreobjectcmd)) {
1207     GeneratePluginEvent(jcr, bEventRestoreObject, nullptr);
1208     return dir->fsend(OKRestoreObject);
1209   }
1210 
1211   rop.plugin_name = (char*)malloc(dir->message_length);
1212   *rop.plugin_name = 0;
1213 
1214   if (sscanf(dir->msg, restoreobjcmd, &rop.JobId, &rop.object_len,
1215              &rop.object_full_len, &rop.object_index, &rop.object_type,
1216              &rop.object_compression, &FileIndex, rop.plugin_name) != 8) {
1217     /*
1218      * Old version, no plugin_name
1219      */
1220     if (sscanf(dir->msg, restoreobjcmd1, &rop.JobId, &rop.object_len,
1221                &rop.object_full_len, &rop.object_index, &rop.object_type,
1222                &rop.object_compression, &FileIndex) != 7) {
1223       Dmsg0(5, "Bad restore object command\n");
1224       PmStrcpy(jcr->errmsg, dir->msg);
1225       Jmsg1(jcr, M_FATAL, 0, _("Bad RestoreObject command: %s\n"), jcr->errmsg);
1226       goto bail_out;
1227     }
1228   }
1229 
1230   UnbashSpaces(rop.plugin_name);
1231 
1232   Dmsg7(100,
1233         "Recv object: JobId=%u objlen=%d full_len=%d objinx=%d objtype=%d "
1234         "FI=%d plugin_name=%s\n",
1235         rop.JobId, rop.object_len, rop.object_full_len, rop.object_index,
1236         rop.object_type, FileIndex, rop.plugin_name);
1237 
1238   /*
1239    * Read Object name
1240    */
1241   if (dir->recv() < 0) { goto bail_out; }
1242   Dmsg2(100, "Recv Oname object: len=%d Oname=%s\n", dir->message_length,
1243         dir->msg);
1244   rop.object_name = strdup(dir->msg);
1245 
1246   /*
1247    * Read Object
1248    */
1249   if (dir->recv() < 0) { goto bail_out; }
1250 
1251   /*
1252    * Transfer object from message buffer, and get new message buffer
1253    */
1254   rop.object = dir->msg;
1255   dir->msg = GetPoolMemory(PM_MESSAGE);
1256 
1257   /*
1258    * If object is compressed, uncompress it
1259    */
1260   switch (rop.object_compression) {
1261     case 1: { /* zlib level 9 */
1262       int status;
1263       int out_len = rop.object_full_len + 100;
1264       POOLMEM* obj = GetMemory(out_len);
1265 
1266       Dmsg2(100, "Inflating from %d to %d\n", rop.object_len,
1267             rop.object_full_len);
1268       status = Zinflate(rop.object, rop.object_len, obj, out_len);
1269       Dmsg1(100, "Zinflate status=%d\n", status);
1270 
1271       if (out_len != rop.object_full_len) {
1272         Jmsg3(jcr, M_ERROR, 0,
1273               ("Decompression failed. Len wanted=%d got=%d. Object_name=%s\n"),
1274               rop.object_full_len, out_len, rop.object_name);
1275       }
1276 
1277       FreePoolMemory(rop.object); /* Release compressed object */
1278       rop.object = obj;           /* New uncompressed object */
1279       rop.object_len = out_len;
1280       break;
1281     }
1282     default:
1283       break;
1284   }
1285 
1286   if (debug_level >= 100) {
1287     PoolMem object_content(PM_MESSAGE);
1288 
1289     /*
1290      * Convert the object into a null terminated string.
1291      */
1292     object_content.check_size(rop.object_len + 1);
1293     memset(object_content.c_str(), 0, rop.object_len + 1);
1294     memcpy(object_content.c_str(), rop.object, rop.object_len);
1295 
1296     Dmsg2(100, "Recv Object: len=%d Object=%s\n", rop.object_len,
1297           object_content.c_str());
1298   }
1299 
1300   /*
1301    * We still need to do this to detect a vss restore
1302    */
1303   if (bstrcmp(rop.object_name, "job_metadata.xml")) {
1304     Dmsg0(100, "got job metadata\n");
1305     jcr->impl->got_metadata = true;
1306   }
1307 
1308   GeneratePluginEvent(jcr, bEventRestoreObject, (void*)&rop);
1309 
1310   if (rop.object_name) { free(rop.object_name); }
1311 
1312   if (rop.object) { FreePoolMemory(rop.object); }
1313 
1314   if (rop.plugin_name) { free(rop.plugin_name); }
1315 
1316   Dmsg1(100, "Send: %s", OKRestoreObject);
1317   return true;
1318 
1319 bail_out:
1320   dir->fsend(_("2909 Bad RestoreObject command.\n"));
1321   return false;
1322 }
1323 
1324 #if defined(WIN32_VSS)
CountIncludeListFileEntries(JobControlRecord * jcr)1325 static inline int CountIncludeListFileEntries(JobControlRecord* jcr)
1326 {
1327   int cnt = 0;
1328   findFILESET* fileset;
1329   findIncludeExcludeItem* incexe;
1330 
1331   fileset = jcr->impl->ff->fileset;
1332   if (fileset) {
1333     for (int i = 0; i < fileset->include_list.size(); i++) {
1334       incexe = (findIncludeExcludeItem*)fileset->include_list.get(i);
1335       cnt += incexe->name_list.size();
1336     }
1337   }
1338 
1339   return cnt;
1340 }
1341 #endif
1342 
1343 /**
1344  * Director is passing his Fileset
1345  */
FilesetCmd(JobControlRecord * jcr)1346 static bool FilesetCmd(JobControlRecord* jcr)
1347 {
1348   BareosSocket* dir = jcr->dir_bsock;
1349   bool retval;
1350 #if defined(WIN32_VSS)
1351   int vss = 0;
1352 
1353   sscanf(dir->msg, "fileset vss=%d", &vss);
1354 #endif
1355 
1356   if (!InitFileset(jcr)) { return false; }
1357 
1358   while (dir->recv() >= 0) {
1359     StripTrailingJunk(dir->msg);
1360     Dmsg1(500, "Fileset: %s\n", dir->msg);
1361     AddFileset(jcr, dir->msg);
1362   }
1363 
1364   if (!TermFileset(jcr)) { return false; }
1365 
1366 #if defined(WIN32_VSS)
1367   jcr->impl->enable_vss =
1368       (vss && (CountIncludeListFileEntries(jcr) > 0)) ? true : false;
1369 #endif
1370 
1371   retval = dir->fsend(OKinc);
1372   GeneratePluginEvent(jcr, bEventEndFileSet);
1373   CheckIncludeListShadowing(jcr, jcr->impl->ff->fileset);
1374 
1375   return retval;
1376 }
1377 
FreeBootstrap(JobControlRecord * jcr)1378 static void FreeBootstrap(JobControlRecord* jcr)
1379 {
1380   if (jcr->RestoreBootstrap) {
1381     SecureErase(jcr, jcr->RestoreBootstrap);
1382     FreePoolMemory(jcr->RestoreBootstrap);
1383     jcr->RestoreBootstrap = nullptr;
1384   }
1385 }
1386 
1387 static pthread_mutex_t bsr_mutex = PTHREAD_MUTEX_INITIALIZER;
1388 static uint32_t bsr_uniq = 0;
1389 
1390 /**
1391  * The Director sends us the bootstrap file, which
1392  * we will in turn pass to the SD.
1393  * Deprecated.  The bsr is now sent directly from the
1394  * Director to the SD.
1395  */
BootstrapCmd(JobControlRecord * jcr)1396 static bool BootstrapCmd(JobControlRecord* jcr)
1397 {
1398   BareosSocket* dir = jcr->dir_bsock;
1399   POOLMEM* fname = GetPoolMemory(PM_FNAME);
1400   FILE* bs;
1401 
1402   FreeBootstrap(jcr);
1403   P(bsr_mutex);
1404   bsr_uniq++;
1405   Mmsg(fname, "%s/%s.%s.%d.bootstrap", me->working_directory,
1406        me->resource_name_, jcr->Job, bsr_uniq);
1407   V(bsr_mutex);
1408   Dmsg1(400, "bootstrap=%s\n", fname);
1409   jcr->RestoreBootstrap = fname;
1410   bs = fopen(fname, "a+b"); /* create file */
1411   if (!bs) {
1412     BErrNo be;
1413     Jmsg(jcr, M_FATAL, 0, _("Could not create bootstrap file %s: ERR=%s\n"),
1414          jcr->RestoreBootstrap, be.bstrerror());
1415     /*
1416      * Suck up what he is sending to us so that he will then
1417      *   read our error message.
1418      */
1419     while (dir->recv() >= 0) {}
1420     FreeBootstrap(jcr);
1421     jcr->setJobStatus(JS_ErrorTerminated);
1422     return false;
1423   }
1424 
1425   while (dir->recv() >= 0) {
1426     Dmsg1(200, "filed<dird: bootstrap: %s", dir->msg);
1427     fputs(dir->msg, bs);
1428   }
1429   fclose(bs);
1430   /*
1431    * Note, do not free the bootstrap yet -- it needs to be sent to the SD
1432    */
1433   return dir->fsend(OKbootstrap);
1434 }
1435 
1436 /**
1437  * Get backup level from Director
1438  */
LevelCmd(JobControlRecord * jcr)1439 static bool LevelCmd(JobControlRecord* jcr)
1440 {
1441   BareosSocket* dir = jcr->dir_bsock;
1442   POOLMEM *level, *buf = nullptr;
1443   int mtime_only;
1444 
1445   level = GetMemory(dir->message_length + 1);
1446   Dmsg1(10, "LevelCmd: %s", dir->msg);
1447 
1448   /*
1449    * Keep compatibility with older directors
1450    */
1451   if (strstr(dir->msg, "accurate")) { jcr->accurate = true; }
1452   if (strstr(dir->msg, "rerunning")) { jcr->rerunning = true; }
1453   if (sscanf(dir->msg, "level = %s ", level) != 1) { goto bail_out; }
1454 
1455   if (bstrcmp(level, "base")) {
1456     /*
1457      * Base backup requested
1458      */
1459     jcr->setJobLevel(L_BASE);
1460   } else if (bstrcmp(level, "full")) {
1461     /*
1462      * Full backup requested
1463      */
1464     jcr->setJobLevel(L_FULL);
1465   } else if (strstr(level, "differential")) {
1466     jcr->setJobLevel(L_DIFFERENTIAL);
1467     FreeMemory(level);
1468     return true;
1469   } else if (strstr(level, "incremental")) {
1470     jcr->setJobLevel(L_INCREMENTAL);
1471     FreeMemory(level);
1472     return true;
1473   } else if (bstrcmp(level, "since_utime")) {
1474     char ed1[50], ed2[50];
1475 
1476     /*
1477      * We get his UTC since time, then sync the clocks and correct it to agree
1478      * with our clock.
1479      */
1480     buf = GetMemory(dir->message_length + 1);
1481     utime_t since_time, adj;
1482     btime_t his_time, bt_start, rt = 0, bt_adj = 0;
1483     if (jcr->getJobLevel() == L_NONE) {
1484       jcr->setJobLevel(L_SINCE); /* if no other job level set, do it now */
1485     }
1486 
1487     if (sscanf(dir->msg, "level = since_utime %s mtime_only=%d prev_job=%127s",
1488                buf, &mtime_only, jcr->impl->PrevJob) != 3) {
1489       if (sscanf(dir->msg, "level = since_utime %s mtime_only=%d", buf,
1490                  &mtime_only) != 2) {
1491         goto bail_out;
1492       }
1493     }
1494 
1495     since_time = str_to_uint64(buf); /* this is the since time */
1496     Dmsg2(100, "since_time=%lld prev_job=%s\n", since_time, jcr->impl->PrevJob);
1497     /*
1498      * Sync clocks by polling him for the time. We take 10 samples of his time
1499      * throwing out the first two.
1500      */
1501     for (int i = 0; i < 10; i++) {
1502       bt_start = GetCurrentBtime();
1503       dir->signal(BNET_BTIME); /* poll for time */
1504       if (dir->recv() <= 0) {  /* get response */
1505         goto bail_out;
1506       }
1507       if (sscanf(dir->msg, "btime %s", buf) != 1) { goto bail_out; }
1508       if (i < 2) { /* toss first two results */
1509         continue;
1510       }
1511       his_time = str_to_uint64(buf);
1512       rt = GetCurrentBtime() - bt_start; /* compute round trip time */
1513       Dmsg2(100, "Dirtime=%s FDtime=%s\n", edit_uint64(his_time, ed1),
1514             edit_uint64(bt_start, ed2));
1515       bt_adj += bt_start - his_time - rt / 2;
1516       Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1),
1517             edit_uint64(bt_adj, ed2));
1518     }
1519 
1520     bt_adj = bt_adj / 8; /* compute average time */
1521     Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1),
1522           edit_uint64(bt_adj, ed2));
1523     adj = BtimeToUtime(bt_adj);
1524     since_time += adj; /* adjust for clock difference */
1525 
1526     /*
1527      * Don't notify if time within 3 seconds
1528      */
1529     if (adj > 3 || adj < -3) {
1530       int type;
1531       if (adj > 600 || adj < -600) {
1532         type = M_WARNING;
1533       } else {
1534         type = M_INFO;
1535       }
1536       Jmsg(jcr, type, 0,
1537            _("DIR and FD clocks differ by %lld seconds, FD automatically "
1538              "compensating.\n"),
1539            adj);
1540     }
1541     dir->signal(BNET_EOD);
1542 
1543     Dmsg2(100, "adj=%lld since_time=%lld\n", adj, since_time);
1544     jcr->impl->incremental = true; /* set incremental or decremental backup */
1545     jcr->impl->mtime = since_time; /* set since time */
1546     GeneratePluginEvent(jcr, bEventSince, (void*)(time_t)jcr->impl->mtime);
1547   } else {
1548     Jmsg1(jcr, M_FATAL, 0, _("Unknown backup level: %s\n"), level);
1549     FreeMemory(level);
1550     return false;
1551   }
1552 
1553   FreeMemory(level);
1554   if (buf) { FreeMemory(buf); }
1555 
1556   GeneratePluginEvent(jcr, bEventLevel, (void*)(intptr_t)jcr->getJobLevel());
1557 
1558   return dir->fsend(OKlevel);
1559 
1560 bail_out:
1561   PmStrcpy(jcr->errmsg, dir->msg);
1562   Jmsg1(jcr, M_FATAL, 0, _("Bad level command: %s\n"), jcr->errmsg);
1563   FreeMemory(level);
1564   if (buf) { FreeMemory(buf); }
1565   return false;
1566 }
1567 
1568 /**
1569  * Get session parameters from Director -- this is for a Restore command
1570  * This is deprecated. It is now passed via the bsr.
1571  */
SessionCmd(JobControlRecord * jcr)1572 static bool SessionCmd(JobControlRecord* jcr)
1573 {
1574   BareosSocket* dir = jcr->dir_bsock;
1575 
1576   Dmsg1(100, "SessionCmd: %s", dir->msg);
1577   if (sscanf(dir->msg, sessioncmd, jcr->VolumeName, &jcr->VolSessionId,
1578              &jcr->VolSessionTime, &jcr->impl->StartFile, &jcr->impl->EndFile,
1579              &jcr->impl->StartBlock, &jcr->impl->EndBlock) != 7) {
1580     PmStrcpy(jcr->errmsg, dir->msg);
1581     Jmsg(jcr, M_FATAL, 0, _("Bad session command: %s"), jcr->errmsg);
1582     return false;
1583   }
1584 
1585   return dir->fsend(OKsession);
1586 }
1587 
SetStorageAuthKeyAndTlsPolicy(JobControlRecord * jcr,char * key,TlsPolicy policy)1588 static void SetStorageAuthKeyAndTlsPolicy(JobControlRecord* jcr,
1589                                           char* key,
1590                                           TlsPolicy policy)
1591 {
1592   /* if no key don't update anything */
1593   if (!*key) { return; }
1594 
1595   /**
1596    * We can be contacting multiple storage daemons.
1597    * So, make sure that any old jcr->store_bsock is cleaned up.
1598    */
1599   if (jcr->store_bsock) {
1600     delete jcr->store_bsock;
1601     jcr->store_bsock = nullptr;
1602   }
1603 
1604   /**
1605    * We can be contacting multiple storage daemons.
1606    * So, make sure that any old jcr->sd_auth_key is cleaned up.
1607    */
1608   if (jcr->sd_auth_key) {
1609     /*
1610      * If we already have a Authorization key, director can do multi storage
1611      * restore
1612      */
1613     Dmsg0(5, "set multi_restore=true\n");
1614     jcr->impl->multi_restore = true;
1615     free(jcr->sd_auth_key);
1616   }
1617 
1618   jcr->sd_auth_key = strdup(key);
1619   Dmsg0(5, "set sd auth key\n");
1620 
1621   jcr->sd_tls_policy = policy;
1622   Dmsg1(5, "set sd ssl_policy to %d\n", policy);
1623 }
1624 
1625 /**
1626  * Get address of storage daemon from Director
1627  */
StorageCmd(JobControlRecord * jcr)1628 static bool StorageCmd(JobControlRecord* jcr)
1629 {
1630   int stored_port;      /* storage daemon port */
1631   TlsPolicy tls_policy; /* enable ssl to sd */
1632   char stored_addr[MAX_NAME_LENGTH];
1633   PoolMem sd_auth_key(PM_MESSAGE);
1634   BareosSocket* dir = jcr->dir_bsock;
1635   BareosSocket* storage_daemon_socket = new BareosSocketTCP;
1636 
1637   if (me->nokeepalive) { storage_daemon_socket->ClearKeepalive(); }
1638   Dmsg1(100, "StorageCmd: %s", dir->msg);
1639   sd_auth_key.check_size(dir->message_length);
1640   if (sscanf(dir->msg, storaddrv1cmd, stored_addr, &stored_port, &tls_policy,
1641              sd_auth_key.c_str()) != 4) {
1642     if (sscanf(dir->msg, storaddrv0cmd, stored_addr, &stored_port,
1643                &tls_policy) != 3) {
1644       PmStrcpy(jcr->errmsg, dir->msg);
1645       Jmsg(jcr, M_FATAL, 0, _("Bad storage command: %s"), jcr->errmsg);
1646       goto bail_out;
1647     }
1648   }
1649 
1650   SetStorageAuthKeyAndTlsPolicy(jcr, sd_auth_key.c_str(), tls_policy);
1651 
1652   Dmsg3(110, "Open storage: %s:%d ssl=%d\n", stored_addr, stored_port,
1653         tls_policy);
1654 
1655   storage_daemon_socket->SetSourceAddress(me->FDsrc_addr);
1656 
1657   /*
1658    * TODO: see if we put limit on restore and backup...
1659    */
1660   if (!jcr->max_bandwidth) {
1661     if (jcr->impl->director->max_bandwidth_per_job) {
1662       jcr->max_bandwidth = jcr->impl->director->max_bandwidth_per_job;
1663     } else if (me->max_bandwidth_per_job) {
1664       jcr->max_bandwidth = me->max_bandwidth_per_job;
1665     }
1666   }
1667 
1668   storage_daemon_socket->SetBwlimit(jcr->max_bandwidth);
1669   if (me->allow_bw_bursting) { storage_daemon_socket->SetBwlimitBursting(); }
1670 
1671   /*
1672    * Open command communications with Storage daemon
1673    */
1674   if (!storage_daemon_socket->connect(
1675           jcr, 10, (int)me->SDConnectTimeout, me->heartbeat_interval,
1676           _("Storage daemon"), stored_addr, nullptr, stored_port, 1)) {
1677     Jmsg(jcr, M_FATAL, 0, _("Failed to connect to Storage daemon: %s:%d\n"),
1678          stored_addr, stored_port);
1679     Dmsg2(100, "Failed to connect to Storage daemon: %s:%d\n", stored_addr,
1680           stored_port);
1681     goto bail_out;
1682   }
1683   Dmsg0(110, "Connection OK to SD.\n");
1684 
1685   jcr->store_bsock = storage_daemon_socket;
1686 
1687   if (tls_policy == TlsPolicy::kBnetTlsAuto) {
1688     std::string qualified_resource_name;
1689     if (!my_config->GetQualifiedResourceNameTypeConverter()->ResourceToString(
1690             jcr->Job, R_JOB, qualified_resource_name)) {
1691       goto bail_out;
1692     }
1693 
1694     if (!storage_daemon_socket->DoTlsHandshake(
1695             TlsPolicy::kBnetTlsAuto, me, false, qualified_resource_name.c_str(),
1696             jcr->sd_auth_key, jcr)) {
1697       jcr->store_bsock = nullptr;
1698       goto bail_out;
1699     }
1700   }
1701 
1702   storage_daemon_socket->InitBnetDump(
1703       my_config->CreateOwnQualifiedNameForNetworkDump());
1704   storage_daemon_socket->fsend("Hello Start Job %s\n", jcr->Job);
1705   if (!AuthenticateWithStoragedaemon(jcr)) {
1706     Jmsg(jcr, M_FATAL, 0, _("Failed to authenticate Storage daemon.\n"));
1707     goto bail_out;
1708   }
1709   Dmsg0(110, "Authenticated with SD.\n");
1710 
1711   /*
1712    * Send OK to Director
1713    */
1714   return dir->fsend(OKstore);
1715 
1716 bail_out:
1717   delete storage_daemon_socket;
1718   jcr->store_bsock = nullptr;
1719   dir->fsend(BADcmd, "storage");
1720   return false;
1721 }
1722 
1723 #ifndef HAVE_WIN32
LogFlagStatus(JobControlRecord * jcr,int flag,const char * flag_text)1724 static void LogFlagStatus(JobControlRecord* jcr,
1725                           int flag,
1726                           const char* flag_text)
1727 {
1728   findFILESET* fileset = jcr->impl->ff->fileset;
1729   bool found = false;
1730   if (fileset) {
1731     for (int i = 0; i < fileset->include_list.size() && !found; i++) {
1732       findIncludeExcludeItem* incexe =
1733           (findIncludeExcludeItem*)fileset->include_list.get(i);
1734 
1735       for (int j = 0; j < incexe->opts_list.size() && !found; j++) {
1736         findFOPTS* fo = (findFOPTS*)incexe->opts_list.get(j);
1737 
1738         if (BitIsSet(flag, fo->flags)) { found = true; }
1739       }
1740     }
1741   }
1742 
1743   std::string m = flag_text;
1744   m += found ? "is enabled\n" : "is disabled\n";
1745   Jmsg(jcr, M_INFO, 0, m.c_str());
1746 }
1747 #endif
1748 
1749 /**
1750  * Clear a flag in the find options.
1751  *
1752  * We walk the list of include blocks and for each option block
1753  * check if a certain flag is set and clear that.
1754  */
ClearFlagInFileset(JobControlRecord * jcr,int flag,const char * warning)1755 static inline void ClearFlagInFileset(JobControlRecord* jcr,
1756                                       int flag,
1757                                       const char* warning)
1758 {
1759   findFILESET* fileset;
1760   bool cleared_flag = false;
1761 
1762   fileset = jcr->impl->ff->fileset;
1763   if (fileset) {
1764     for (int i = 0; i < fileset->include_list.size(); i++) {
1765       findIncludeExcludeItem* incexe =
1766           (findIncludeExcludeItem*)fileset->include_list.get(i);
1767 
1768       for (int j = 0; j < incexe->opts_list.size(); j++) {
1769         findFOPTS* fo = (findFOPTS*)incexe->opts_list.get(j);
1770 
1771         if (BitIsSet(flag, fo->flags)) {
1772           ClearBit(flag, fo->flags);
1773           cleared_flag = true;
1774         }
1775       }
1776     }
1777   }
1778 
1779   if (cleared_flag) { Jmsg(jcr, M_WARNING, 0, warning); }
1780 }
1781 
1782 /**
1783  * Clear a compression flag in the find options.
1784  *
1785  * We walk the list of include blocks and for each option block
1786  * check if a certain compression flag is set and clear that.
1787  */
ClearCompressionFlagInFileset(JobControlRecord * jcr)1788 static inline void ClearCompressionFlagInFileset(JobControlRecord* jcr)
1789 {
1790   findFILESET* fileset;
1791 
1792   fileset = jcr->impl->ff->fileset;
1793   if (fileset) {
1794     for (int i = 0; i < fileset->include_list.size(); i++) {
1795       findIncludeExcludeItem* incexe =
1796           (findIncludeExcludeItem*)fileset->include_list.get(i);
1797 
1798       for (int j = 0; j < incexe->opts_list.size(); j++) {
1799         findFOPTS* fo = (findFOPTS*)incexe->opts_list.get(j);
1800 
1801         /*
1802          * See if a compression flag is set in this option block.
1803          */
1804         if (BitIsSet(FO_COMPRESS, fo->flags)) {
1805           switch (fo->Compress_algo) {
1806 #if defined(HAVE_LIBZ)
1807             case COMPRESS_GZIP:
1808               break;
1809 #endif
1810 #if defined(HAVE_LZO)
1811             case COMPRESS_LZO1X:
1812               break;
1813 #endif
1814             case COMPRESS_FZFZ:
1815             case COMPRESS_FZ4L:
1816             case COMPRESS_FZ4H:
1817               break;
1818             default:
1819               /*
1820                * When we get here its because the wanted compression protocol is
1821                * not supported with the current compile options.
1822                */
1823               Jmsg(jcr, M_WARNING, 0,
1824                    "%s compression support requested in fileset but not "
1825                    "available on this platform. Disabling "
1826                    "...\n",
1827                    cmprs_algo_to_text(fo->Compress_algo));
1828               ClearBit(FO_COMPRESS, fo->flags);
1829               fo->Compress_algo = 0;
1830               break;
1831           }
1832         }
1833       }
1834     }
1835   }
1836 }
1837 
1838 /**
1839  * Find out what encryption cipher to use.
1840  */
GetWantedCryptoCipher(JobControlRecord * jcr,crypto_cipher_t * cipher)1841 static inline bool GetWantedCryptoCipher(JobControlRecord* jcr,
1842                                          crypto_cipher_t* cipher)
1843 {
1844   findFILESET* fileset;
1845   bool force_encrypt = false;
1846   crypto_cipher_t wanted_cipher = CRYPTO_CIPHER_NONE;
1847 
1848   /*
1849    * Walk the fileset and check for the FO_FORCE_ENCRYPT flag and any forced
1850    * crypto cipher.
1851    */
1852   fileset = jcr->impl->ff->fileset;
1853   if (fileset) {
1854     for (int i = 0; i < fileset->include_list.size(); i++) {
1855       findIncludeExcludeItem* incexe =
1856           (findIncludeExcludeItem*)fileset->include_list.get(i);
1857 
1858       for (int j = 0; j < incexe->opts_list.size(); j++) {
1859         findFOPTS* fo = (findFOPTS*)incexe->opts_list.get(j);
1860 
1861         if (BitIsSet(FO_FORCE_ENCRYPT, fo->flags)) { force_encrypt = true; }
1862 
1863         if (fo->Encryption_cipher != CRYPTO_CIPHER_NONE) {
1864           /*
1865            * Make sure we have not found a cipher definition before.
1866            */
1867           if (wanted_cipher != CRYPTO_CIPHER_NONE) {
1868             Jmsg(jcr, M_FATAL, 0,
1869                  _("Fileset contains multiple cipher settings\n"));
1870             return false;
1871           }
1872 
1873           /*
1874            * See if pki_encrypt is already set for this Job.
1875            */
1876           if (!jcr->impl->crypto.pki_encrypt) {
1877             if (!me->pki_keypair_file) {
1878               Jmsg(jcr, M_FATAL, 0,
1879                    _("Fileset contains cipher settings but PKI Key Pair is not "
1880                      "configured\n"));
1881               return false;
1882             }
1883 
1884             /*
1885              * Enable encryption and signing for this Job.
1886              */
1887             jcr->impl->crypto.pki_sign = true;
1888             jcr->impl->crypto.pki_encrypt = true;
1889           }
1890 
1891           wanted_cipher = (crypto_cipher_t)fo->Encryption_cipher;
1892         }
1893       }
1894     }
1895   }
1896 
1897   /*
1898    * See if fileset forced a certain cipher.
1899    */
1900   if (wanted_cipher == CRYPTO_CIPHER_NONE) { wanted_cipher = me->pki_cipher; }
1901 
1902   /*
1903    * See if we are in compatible mode then we are hardcoded to
1904    * CRYPTO_CIPHER_AES_128_CBC.
1905    */
1906   if (me->compatible) { wanted_cipher = CRYPTO_CIPHER_AES_128_CBC; }
1907 
1908   /*
1909    * See if FO_FORCE_ENCRYPT is set and encryption is not configured for the
1910    * filed.
1911    */
1912   if (force_encrypt && !jcr->impl->crypto.pki_encrypt) {
1913     Jmsg(jcr, M_FATAL, 0,
1914          _("Fileset forces encryption but encryption is not configured\n"));
1915     return false;
1916   }
1917 
1918   *cipher = wanted_cipher;
1919 
1920   return true;
1921 }
1922 
1923 /**
1924  * Do a backup.
1925  */
BackupCmd(JobControlRecord * jcr)1926 static bool BackupCmd(JobControlRecord* jcr)
1927 {
1928   int ok = 0;
1929   int SDJobStatus;
1930   int32_t FileIndex;
1931   BareosSocket* dir = jcr->dir_bsock;
1932   BareosSocket* sd = jcr->store_bsock;
1933   crypto_cipher_t cipher = CRYPTO_CIPHER_NONE;
1934 
1935   /*
1936    * See if we are in restore only mode then we don't allow a backup to be
1937    * initiated.
1938    */
1939   if (restore_only_mode) {
1940     Jmsg(jcr, M_FATAL, 0,
1941          _("Filed in restore only mode, backups are not allowed, "
1942            "aborting...\n"));
1943     goto cleanup;
1944   }
1945 
1946   /*
1947    * See if we are allowed to run backup cmds.
1948    */
1949   if (!ValidateCommand(
1950           jcr, "backup",
1951           (jcr->impl->director && jcr->impl->director->allowed_job_cmds)
1952               ? jcr->impl->director->allowed_job_cmds
1953               : me->allowed_job_cmds)) {
1954     goto cleanup;
1955   }
1956 
1957 #if defined(WIN32_VSS)
1958   if (jcr->impl->enable_vss) { VSSInit(jcr); }
1959 #endif
1960 
1961   if (sscanf(dir->msg, "backup FileIndex=%ld\n", &FileIndex) == 1) {
1962     jcr->JobFiles = FileIndex;
1963     Dmsg1(100, "JobFiles=%ld\n", jcr->JobFiles);
1964   }
1965 
1966   /**
1967    * Validate some options given to the backup make sense for the compiled in
1968    * options of this filed.
1969    */
1970 #ifndef HAVE_WIN32
1971   if (!have_acl) {
1972     ClearFlagInFileset(jcr, FO_ACL,
1973                        _("ACL support requested in fileset but not available "
1974                          "on this platform. Disabling ...\n"));
1975   }
1976 
1977   if (!have_xattr) {
1978     ClearFlagInFileset(jcr, FO_XATTR,
1979                        _("XATTR support requested in fileset but not available "
1980                          "on this platform. Disabling ...\n"));
1981   }
1982 #endif
1983   if (!have_encryption) {
1984     ClearFlagInFileset(jcr, FO_ENCRYPT,
1985                        _("Encryption support requested in fileset but not "
1986                          "available on this platform. Disabling ...\n"));
1987   }
1988 
1989   ClearCompressionFlagInFileset(jcr);
1990 
1991 #ifndef HAVE_WIN32
1992   LogFlagStatus(jcr, FO_XATTR, "Extended attribute support ");
1993   LogFlagStatus(jcr, FO_ACL, "ACL support ");
1994 #endif
1995   if (!GetWantedCryptoCipher(jcr, &cipher)) {
1996     dir->fsend(BADcmd, "backup");
1997     goto cleanup;
1998   }
1999 
2000   jcr->setJobStatus(JS_Blocked);
2001   jcr->setJobType(JT_BACKUP);
2002   Dmsg1(100, "begin backup ff=%p\n", jcr->impl->ff);
2003 
2004   if (sd == nullptr) {
2005     Jmsg(jcr, M_FATAL, 0, _("Cannot contact Storage daemon\n"));
2006     dir->fsend(BADcmd, "backup");
2007     goto cleanup;
2008   }
2009 
2010   dir->fsend(OKbackup);
2011   Dmsg1(110, "filed>dird: %s", dir->msg);
2012 
2013   /**
2014    * Send Append Open Session to Storage daemon
2015    */
2016   sd->fsend(append_open);
2017   Dmsg1(110, ">stored: %s", sd->msg);
2018 
2019   /**
2020    * Expect to receive back the Ticket number
2021    */
2022   if (BgetMsg(sd) >= 0) {
2023     Dmsg1(110, "<stored: %s", sd->msg);
2024     if (sscanf(sd->msg, OK_open, &jcr->impl->Ticket) != 1) {
2025       Jmsg(jcr, M_FATAL, 0, _("Bad response to append open: %s\n"), sd->msg);
2026       goto cleanup;
2027     }
2028     Dmsg1(110, "Got Ticket=%d\n", jcr->impl->Ticket);
2029   } else {
2030     Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to open command\n"));
2031     goto cleanup;
2032   }
2033 
2034   /**
2035    * Send Append data command to Storage daemon
2036    */
2037   sd->fsend(append_data, jcr->impl->Ticket);
2038   Dmsg1(110, ">stored: %s", sd->msg);
2039 
2040   /**
2041    * Expect to get OK data
2042    */
2043   if (!response(jcr, sd, OK_data, "Append Data")) {
2044     Dmsg1(110, "<stored: %s", sd->msg);
2045     goto cleanup;
2046   }
2047   Dmsg1(110, "<stored: %s", sd->msg);
2048 
2049   GeneratePluginEvent(jcr, bEventStartBackupJob);
2050 
2051 #if defined(WIN32_VSS)
2052   /*
2053    * START VSS ON WIN32
2054    */
2055   if (jcr->impl->pVSSClient) {
2056     if (jcr->impl->pVSSClient->InitializeForBackup(jcr)) {
2057       int drive_count;
2058       char szWinDriveLetters[27];
2059       bool onefs_disabled;
2060 
2061       GeneratePluginEvent(jcr, bEventVssBackupAddComponents);
2062 
2063       /*
2064        * Tell vss which drives to snapshot
2065        */
2066       *szWinDriveLetters = 0;
2067 
2068       /*
2069        * Plugin driver can return drive letters
2070        */
2071       GeneratePluginEvent(jcr, bEventVssPrepareSnapshot, szWinDriveLetters);
2072 
2073       drive_count =
2074           get_win32_driveletters(jcr->impl->ff->fileset, szWinDriveLetters);
2075 
2076       onefs_disabled = win32_onefs_is_disabled(jcr->impl->ff->fileset);
2077 
2078       if (drive_count > 0) {
2079         Jmsg(jcr, M_INFO, 0,
2080              _("Generate VSS snapshots. Driver=\"%s\", Drive(s)=\"%s\"\n"),
2081              jcr->impl->pVSSClient->GetDriverName(),
2082              (drive_count) ? szWinDriveLetters : "None");
2083 
2084         if (!jcr->impl->pVSSClient->CreateSnapshots(szWinDriveLetters,
2085                                                     onefs_disabled)) {
2086           BErrNo be;
2087           Jmsg(jcr, M_FATAL, 0,
2088                _("CreateSGenerate VSS snapshots failed. ERR=%s\n"),
2089                be.bstrerror());
2090         } else {
2091           GeneratePluginEvent(jcr, bEventVssCreateSnapshots);
2092 
2093           /*
2094            * Inform about VMPs if we have them
2095            */
2096           jcr->impl->pVSSClient->ShowVolumeMountPointStats(jcr);
2097 
2098           /*
2099            * Tell user if snapshot creation of a specific drive failed
2100            */
2101           for (int i = 0; i < (int)strlen(szWinDriveLetters); i++) {
2102             if (islower(szWinDriveLetters[i])) {
2103               Jmsg(jcr, M_FATAL, 0,
2104                    _("Generate VSS snapshot of drive \"%c:\\\" failed.\n"),
2105                    szWinDriveLetters[i]);
2106             }
2107           }
2108 
2109           /*
2110            * Inform user about writer states
2111            */
2112           for (size_t i = 0; i < jcr->impl->pVSSClient->GetWriterCount(); i++) {
2113             if (jcr->impl->pVSSClient->GetWriterState(i) < 1) {
2114               Jmsg(jcr, M_INFO, 0, _("VSS Writer (PrepareForBackup): %s\n"),
2115                    jcr->impl->pVSSClient->GetWriterInfo(i));
2116             }
2117           }
2118         }
2119 
2120       } else {
2121         Jmsg(jcr, M_FATAL, 0,
2122              _("No drive letters found for generating VSS snapshots.\n"));
2123       }
2124     } else {
2125       BErrNo be;
2126 
2127       Jmsg(jcr, M_FATAL, 0, _("VSS was not initialized properly. ERR=%s\n"),
2128            be.bstrerror());
2129     }
2130 
2131     RunScripts(jcr, jcr->impl->RunScripts, "ClientAfterVSS",
2132                (jcr->impl->director && jcr->impl->director->allowed_script_dirs)
2133                    ? jcr->impl->director->allowed_script_dirs
2134                    : me->allowed_script_dirs);
2135   }
2136 #endif
2137 
2138   /**
2139    * Send Files to Storage daemon
2140    */
2141   Dmsg1(110, "begin blast ff=%p\n", (FindFilesPacket*)jcr->impl->ff);
2142   if (!BlastDataToStorageDaemon(jcr, nullptr, cipher)) {
2143     jcr->setJobStatus(JS_ErrorTerminated);
2144     BnetSuppressErrorMessages(sd, 1);
2145     Dmsg0(110, "Error in blast_data.\n");
2146   } else {
2147     jcr->setJobStatus(JS_Terminated);
2148     /* Note, the above set status will not override an error */
2149     if (!jcr->IsTerminatedOk()) {
2150       BnetSuppressErrorMessages(sd, 1);
2151       goto cleanup; /* bail out now */
2152     }
2153     /**
2154      * Expect to get response to append_data from Storage daemon
2155      */
2156     if (!response(jcr, sd, OK_append, "Append Data")) {
2157       jcr->setJobStatus(JS_ErrorTerminated);
2158       goto cleanup;
2159     }
2160 
2161     /**
2162      * Send Append End Data to Storage daemon
2163      */
2164     sd->fsend(append_end, jcr->impl->Ticket);
2165     /* Get end OK */
2166     if (!response(jcr, sd, OK_end, "Append End")) {
2167       jcr->setJobStatus(JS_ErrorTerminated);
2168       goto cleanup;
2169     }
2170 
2171     /**
2172      * Send Append Close to Storage daemon
2173      */
2174     sd->fsend(append_close, jcr->impl->Ticket);
2175     while (BgetMsg(sd) >= 0) { /* stop on signal or error */
2176       if (sscanf(sd->msg, OK_close, &SDJobStatus) == 1) {
2177         ok = 1;
2178         Dmsg2(200, "SDJobStatus = %d %c\n", SDJobStatus, (char)SDJobStatus);
2179       }
2180     }
2181     if (!ok) {
2182       Jmsg(jcr, M_FATAL, 0, _("Append Close with SD failed.\n"));
2183       goto cleanup;
2184     }
2185     if (!(SDJobStatus == JS_Terminated || SDJobStatus == JS_Warnings)) {
2186       Jmsg(jcr, M_FATAL, 0, _("Bad status %d returned from Storage Daemon.\n"),
2187            SDJobStatus);
2188     }
2189   }
2190 
2191 cleanup:
2192 #if defined(WIN32_VSS)
2193   if (jcr->impl->pVSSClient) { jcr->impl->pVSSClient->DestroyWriterInfo(); }
2194 #endif
2195 
2196   GeneratePluginEvent(jcr, bEventEndBackupJob);
2197   return false; /* return and stop command loop */
2198 }
2199 
2200 /**
2201  * Do a Verify for Director
2202  *
2203  */
VerifyCmd(JobControlRecord * jcr)2204 static bool VerifyCmd(JobControlRecord* jcr)
2205 {
2206   char level[100];
2207   BareosSocket* dir = jcr->dir_bsock;
2208   BareosSocket* sd = jcr->store_bsock;
2209 
2210   /*
2211    * See if we are allowed to run verify cmds.
2212    */
2213   if (!ValidateCommand(
2214           jcr, "verify",
2215           (jcr->impl->director && jcr->impl->director->allowed_job_cmds)
2216               ? jcr->impl->director->allowed_job_cmds
2217               : me->allowed_job_cmds)) {
2218     dir->fsend(_("2994 Bad verify command: %s\n"), dir->msg);
2219     return 0;
2220   }
2221 
2222   jcr->setJobType(JT_VERIFY);
2223   if (sscanf(dir->msg, verifycmd, level) != 1) {
2224     dir->fsend(_("2994 Bad verify command: %s\n"), dir->msg);
2225     return false;
2226   }
2227 
2228   if (Bstrcasecmp(level, "init")) {
2229     jcr->setJobLevel(L_VERIFY_INIT);
2230   } else if (Bstrcasecmp(level, "catalog")) {
2231     jcr->setJobLevel(L_VERIFY_CATALOG);
2232   } else if (Bstrcasecmp(level, "volume")) {
2233     jcr->setJobLevel(L_VERIFY_VOLUME_TO_CATALOG);
2234   } else if (Bstrcasecmp(level, "data")) {
2235     jcr->setJobLevel(L_VERIFY_DATA);
2236   } else if (Bstrcasecmp(level, "disk_to_catalog")) {
2237     jcr->setJobLevel(L_VERIFY_DISK_TO_CATALOG);
2238   } else {
2239     dir->fsend(_("2994 Bad verify level: %s\n"), dir->msg);
2240     return false;
2241   }
2242 
2243   dir->fsend(OKverify);
2244 
2245   GeneratePluginEvent(jcr, bEventLevel, (void*)(intptr_t)jcr->getJobLevel());
2246   GeneratePluginEvent(jcr, bEventStartVerifyJob);
2247 
2248   Dmsg1(110, "filed>dird: %s", dir->msg);
2249 
2250   switch (jcr->getJobLevel()) {
2251     case L_VERIFY_INIT:
2252     case L_VERIFY_CATALOG:
2253       DoVerify(jcr);
2254       break;
2255     case L_VERIFY_VOLUME_TO_CATALOG:
2256       if (!OpenSdReadSession(jcr)) { return false; }
2257       StartDirHeartbeat(jcr);
2258       DoVerifyVolume(jcr);
2259       StopDirHeartbeat(jcr);
2260       /*
2261        * Send Close session command to Storage daemon
2262        */
2263       sd->fsend(read_close, jcr->impl->Ticket);
2264       Dmsg1(130, "filed>stored: %s", sd->msg);
2265 
2266       /* ****FIXME**** check response */
2267       BgetMsg(sd); /* get OK */
2268 
2269       /* Inform Storage daemon that we are done */
2270       sd->signal(BNET_TERMINATE);
2271 
2272       break;
2273     case L_VERIFY_DISK_TO_CATALOG:
2274       DoVerify(jcr);
2275       break;
2276     default:
2277       dir->fsend(_("2994 Bad verify level: %s\n"), dir->msg);
2278       return false;
2279   }
2280 
2281   dir->signal(BNET_EOD);
2282   GeneratePluginEvent(jcr, bEventEndVerifyJob);
2283   return false; /* return and Terminate command loop */
2284 }
2285 
2286 /**
2287  * Open connection to Director.
2288  */
connect_to_director(JobControlRecord * jcr,DirectorResource * dir_res,bool verbose)2289 static BareosSocket* connect_to_director(JobControlRecord* jcr,
2290                                          DirectorResource* dir_res,
2291                                          bool verbose)
2292 {
2293   ASSERT(dir_res != nullptr);
2294 
2295   std::unique_ptr<BareosSocket> director_socket =
2296       std::make_unique<BareosSocketTCP>();
2297 
2298   if (me->nokeepalive) { director_socket->ClearKeepalive(); }
2299 
2300   director_socket->SetSourceAddress(me->FDsrc_addr);
2301 
2302   int retry_interval = 0;
2303   int max_retry_time = 0;
2304   utime_t heart_beat = me->heartbeat_interval;
2305   if (!director_socket->connect(jcr, retry_interval, max_retry_time, heart_beat,
2306                                 dir_res->resource_name_, dir_res->address,
2307                                 nullptr, dir_res->port, verbose)) {
2308     return nullptr;
2309   }
2310 
2311   if (dir_res->IsTlsConfigured()) {
2312     std::string qualified_resource_name;
2313     if (!my_config->GetQualifiedResourceNameTypeConverter()->ResourceToString(
2314             me->resource_name_, my_config->r_own_, qualified_resource_name)) {
2315       Dmsg0(100,
2316             "Could not generate qualified resource name for a storage "
2317             "resource\n");
2318       return nullptr;
2319     }
2320 
2321     if (!director_socket->DoTlsHandshake(TlsPolicy::kBnetTlsAuto, dir_res,
2322                                          false, qualified_resource_name.c_str(),
2323                                          dir_res->password_.value, jcr)) {
2324       Dmsg0(100, "Could not DoTlsHandshake() with director\n");
2325       return nullptr;
2326     }
2327   }
2328 
2329   Dmsg1(10, "Opened connection with Director %s\n", dir_res->resource_name_);
2330   jcr->dir_bsock = director_socket.get();
2331 
2332   director_socket->InitBnetDump(
2333       my_config->CreateOwnQualifiedNameForNetworkDump());
2334   director_socket->fsend(hello_client, my_name, FD_PROTOCOL_VERSION);
2335   if (!AuthenticateWithDirector(jcr, dir_res)) {
2336     jcr->dir_bsock = nullptr;
2337     return nullptr;
2338   }
2339 
2340   director_socket->recv();
2341   ParseOkVersion(director_socket->msg);
2342 
2343   jcr->impl->director = dir_res;
2344 
2345   return director_socket.release();
2346 }
2347 
2348 /**
2349  * Do a Restore for Director
2350  */
RestoreCmd(JobControlRecord * jcr)2351 static bool RestoreCmd(JobControlRecord* jcr)
2352 {
2353   BareosSocket* dir = jcr->dir_bsock;
2354   BareosSocket* sd = jcr->store_bsock;
2355   POOLMEM* args;
2356   bool use_regexwhere = false;
2357   bool retval;
2358   int prefix_links;
2359   char replace;
2360 
2361   /*
2362    * See if we are in backup only mode then we don't allow a restore to be
2363    * initiated.
2364    */
2365   if (backup_only_mode) {
2366     Jmsg(jcr, M_FATAL, 0,
2367          _("Filed in backup only mode, restores are not allowed, "
2368            "aborting...\n"));
2369     return false;
2370   }
2371 
2372   /*
2373    * See if we are allowed to run restore cmds.
2374    */
2375   if (!ValidateCommand(
2376           jcr, "restore",
2377           (jcr->impl->director && jcr->impl->director->allowed_job_cmds)
2378               ? jcr->impl->director->allowed_job_cmds
2379               : me->allowed_job_cmds)) {
2380     return 0;
2381   }
2382 
2383   jcr->setJobType(JT_RESTORE);
2384 
2385   /**
2386    * Scan WHERE (base directory for restore) from command
2387    */
2388   Dmsg0(100, "restore command\n");
2389 
2390   /*
2391    * Pickup where string
2392    */
2393   args = GetMemory(dir->message_length + 1);
2394   *args = 0;
2395 
2396   if (sscanf(dir->msg, restorecmd, &replace, &prefix_links, args) != 3) {
2397     if (sscanf(dir->msg, restorecmdR, &replace, &prefix_links, args) != 3) {
2398       if (sscanf(dir->msg, restorecmd1, &replace, &prefix_links) != 2) {
2399         PmStrcpy(jcr->errmsg, dir->msg);
2400         Jmsg(jcr, M_FATAL, 0, _("Bad replace command. CMD=%s\n"), jcr->errmsg);
2401         FreePoolMemory(args);
2402         return false;
2403       }
2404       *args = 0;
2405     }
2406     use_regexwhere = true;
2407   }
2408 
2409 #if defined(WIN32_VSS)
2410   /**
2411    * No need to enable VSS for restore if we do not have plugin data to restore
2412    */
2413   jcr->impl->enable_vss = jcr->impl->got_metadata;
2414 
2415   if (jcr->impl->enable_vss) { VSSInit(jcr); }
2416 #endif
2417 
2418   /*
2419    * Turn / into nothing
2420    */
2421   if (IsPathSeparator(args[0]) && args[1] == '\0') { args[0] = '\0'; }
2422 
2423   Dmsg2(150, "Got replace %c, where=%s\n", replace, args);
2424   UnbashSpaces(args);
2425 
2426   /*
2427    * Keep track of newly created directories to apply them correct attributes
2428    */
2429   if (replace == REPLACE_NEVER) { jcr->keep_path_list = true; }
2430 
2431   if (use_regexwhere) {
2432     jcr->where_bregexp = get_bregexps(args);
2433     if (!jcr->where_bregexp) {
2434       Jmsg(jcr, M_FATAL, 0, _("Bad where regexp. where=%s\n"), args);
2435       FreePoolMemory(args);
2436       return false;
2437     }
2438   } else {
2439     jcr->where = strdup(args);
2440   }
2441 
2442   FreePoolMemory(args);
2443   jcr->impl->replace = replace;
2444   jcr->prefix_links = prefix_links;
2445 
2446   dir->fsend(OKrestore);
2447   Dmsg1(110, "filed>dird: %s", dir->msg);
2448 
2449   jcr->setJobStatus(JS_Blocked);
2450 
2451   if (!OpenSdReadSession(jcr)) {
2452     jcr->setJobStatus(JS_ErrorTerminated);
2453     goto bail_out;
2454   }
2455 
2456   jcr->setJobStatus(JS_Running);
2457 
2458   /**
2459    * Do restore of files and data
2460    */
2461   StartDirHeartbeat(jcr);
2462   GeneratePluginEvent(jcr, bEventStartRestoreJob);
2463 
2464 #if defined(WIN32_VSS)
2465   /*
2466    * START VSS ON WIN32
2467    */
2468   if (jcr->impl->pVSSClient) {
2469     if (!jcr->impl->pVSSClient->InitializeForRestore(jcr)) {
2470       BErrNo be;
2471       Jmsg(jcr, M_WARNING, 0,
2472            _("VSS was not initialized properly. VSS support is disabled. "
2473              "ERR=%s\n"),
2474            be.bstrerror());
2475     }
2476 
2477     GeneratePluginEvent(jcr, bEventVssRestoreLoadComponentMetadata);
2478 
2479     RunScripts(jcr, jcr->impl->RunScripts, "ClientAfterVSS",
2480                (jcr->impl->director && jcr->impl->director->allowed_script_dirs)
2481                    ? jcr->impl->director->allowed_script_dirs
2482                    : me->allowed_script_dirs);
2483   }
2484 #endif
2485 
2486   DoRestore(jcr);
2487   StopDirHeartbeat(jcr);
2488 
2489   if (jcr->JobWarnings) {
2490     jcr->setJobStatus(JS_Warnings);
2491   } else {
2492     jcr->setJobStatus(JS_Terminated);
2493   }
2494 
2495   /**
2496    * Send Close session command to Storage daemon
2497    */
2498   sd->fsend(read_close, jcr->impl->Ticket);
2499   Dmsg1(100, "filed>stored: %s", sd->msg);
2500 
2501   BgetMsg(sd); /* get OK */
2502 
2503   /* Inform Storage daemon that we are done */
2504   sd->signal(BNET_TERMINATE);
2505 
2506 #if defined(WIN32_VSS)
2507   /*
2508    * STOP VSS ON WIN32
2509    * Tell vss to close the restore session
2510    */
2511   if (jcr->impl->pVSSClient) {
2512     Dmsg0(100, "About to call CloseRestore\n");
2513 
2514     GeneratePluginEvent(jcr, bEventVssCloseRestore);
2515 
2516     Dmsg0(100, "Really about to call CloseRestore\n");
2517     if (jcr->impl->pVSSClient->CloseRestore()) {
2518       Dmsg0(100, "CloseRestore success\n");
2519       /*
2520        * Inform user about writer states
2521        */
2522       for (size_t i = 0; i < jcr->impl->pVSSClient->GetWriterCount(); i++) {
2523         int msg_type = M_INFO;
2524 
2525         if (jcr->impl->pVSSClient->GetWriterState(i) < 1) {
2526           msg_type = M_WARNING;
2527           jcr->JobErrors++;
2528         }
2529         Jmsg(jcr, msg_type, 0, _("VSS Writer (RestoreComplete): %s\n"),
2530              jcr->impl->pVSSClient->GetWriterInfo(i));
2531       }
2532     } else {
2533       Dmsg1(100, "CloseRestore fail - %08x\n", errno);
2534     }
2535   }
2536 #endif
2537 
2538 bail_out:
2539   BfreeAndNull(jcr->where);
2540 
2541   if (jcr->JobErrors) { jcr->setJobStatus(JS_ErrorTerminated); }
2542 
2543   Dmsg0(100, "Done in job.c\n");
2544 
2545   if (jcr->impl->multi_restore) {
2546     Dmsg0(100, OKstoreend);
2547     dir->fsend(OKstoreend);
2548     retval = true; /* we continue the loop, waiting for next part */
2549   } else {
2550     retval = false; /* we stop here */
2551   }
2552 
2553   if (JobCanceled(jcr)) { retval = false; /* we stop here */ }
2554 
2555   if (!retval) {
2556     EndRestoreCmd(jcr); /* stopping so send bEventEndRestoreJob */
2557   }
2558 
2559   return retval;
2560 }
2561 
EndRestoreCmd(JobControlRecord * jcr)2562 static bool EndRestoreCmd(JobControlRecord* jcr)
2563 {
2564   Dmsg0(5, "EndRestoreCmd\n");
2565   GeneratePluginEvent(jcr, bEventEndRestoreJob);
2566   return false; /* return and Terminate command loop */
2567 }
2568 
OpenSdReadSession(JobControlRecord * jcr)2569 static bool OpenSdReadSession(JobControlRecord* jcr)
2570 {
2571   BareosSocket* sd = jcr->store_bsock;
2572 
2573   if (!sd) {
2574     Jmsg(jcr, M_FATAL, 0, _("Improper calling sequence.\n"));
2575     return false;
2576   }
2577   Dmsg4(120, "VolSessId=%ld VolsessT=%ld SF=%ld EF=%ld\n", jcr->VolSessionId,
2578         jcr->VolSessionTime, jcr->impl->StartFile, jcr->impl->EndFile);
2579   Dmsg2(120, "JobId=%d vol=%s\n", jcr->JobId, "DummyVolume");
2580   /*
2581    * Open Read Session with Storage daemon
2582    */
2583   sd->fsend(read_open, "DummyVolume", jcr->VolSessionId, jcr->VolSessionTime,
2584             jcr->impl->StartFile, jcr->impl->EndFile, jcr->impl->StartBlock,
2585             jcr->impl->EndBlock);
2586   Dmsg1(110, ">stored: %s", sd->msg);
2587 
2588   /*
2589    * Get ticket number
2590    */
2591   if (BgetMsg(sd) >= 0) {
2592     Dmsg1(110, "filed<stored: %s", sd->msg);
2593     if (sscanf(sd->msg, OK_open, &jcr->impl->Ticket) != 1) {
2594       Jmsg(jcr, M_FATAL, 0, _("Bad response to SD read open: %s\n"), sd->msg);
2595       return false;
2596     }
2597     Dmsg1(110, "filed: got Ticket=%d\n", jcr->impl->Ticket);
2598   } else {
2599     Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to read open command\n"));
2600     return false;
2601   }
2602 
2603   /*
2604    * Start read of data with Storage daemon
2605    */
2606   sd->fsend(read_data, jcr->impl->Ticket);
2607   Dmsg1(110, ">stored: %s", sd->msg);
2608 
2609   /*
2610    * Get OK data
2611    */
2612   if (!response(jcr, sd, OK_data, "Read Data")) { return false; }
2613 
2614   return true;
2615 }
2616 
2617 /**
2618  * Destroy the Job Control Record and associated resources (sockets).
2619  */
FiledFreeJcr(JobControlRecord * jcr)2620 static void FiledFreeJcr(JobControlRecord* jcr)
2621 {
2622 #if defined(WIN32_VSS)
2623   if (jcr->impl->pVSSClient) {
2624     delete jcr->impl->pVSSClient;
2625     jcr->impl->pVSSClient = nullptr;
2626   }
2627 #endif
2628 
2629   if (jcr->store_bsock) {
2630     jcr->store_bsock->close();
2631     delete jcr->store_bsock;
2632     jcr->store_bsock = nullptr;
2633   }
2634 
2635   if (jcr->dir_bsock) {
2636     jcr->dir_bsock->close();
2637     delete jcr->dir_bsock;
2638     jcr->dir_bsock = nullptr;
2639   }
2640 
2641   if (jcr->impl->last_fname) { FreePoolMemory(jcr->impl->last_fname); }
2642 
2643   FreeBootstrap(jcr);
2644   FreeRunscripts(jcr->impl->RunScripts);
2645   delete jcr->impl->RunScripts;
2646   jcr->impl->RunScripts = nullptr;
2647 
2648   if (jcr->path_list) {
2649     FreePathList(jcr->path_list);
2650     jcr->path_list = nullptr;
2651   }
2652 
2653   TermFindFiles(jcr->impl->ff);
2654   jcr->impl->ff = nullptr;
2655 
2656   if (jcr->JobId != 0) {
2657     WriteStateFile(me->working_directory, "bareos-fd",
2658                    GetFirstPortHostOrder(me->FDaddrs));
2659   }
2660 
2661   if (jcr->impl) {
2662     delete jcr->impl;
2663     jcr->impl = nullptr;
2664   }
2665 
2666   return;
2667 }
2668 
2669 /**
2670  * Get response from Storage daemon to a command we sent.
2671  * Check that the response is OK.
2672  *
2673  * Returns: false on failure
2674  *          true on success
2675  */
response(JobControlRecord * jcr,BareosSocket * sd,char * resp,const char * cmd)2676 bool response(JobControlRecord* jcr,
2677               BareosSocket* sd,
2678               char* resp,
2679               const char* cmd)
2680 {
2681   if (sd->errors) { return false; }
2682   if (BgetMsg(sd) > 0) {
2683     Dmsg0(110, sd->msg);
2684     if (bstrcmp(sd->msg, resp)) { return true; }
2685   }
2686   if (JobCanceled(jcr)) {
2687     return false; /* if canceled avoid useless error messages */
2688   }
2689   if (IsBnetError(sd)) {
2690     Jmsg2(jcr, M_FATAL, 0,
2691           _("Comm error with SD. bad response to %s. ERR=%s\n"), cmd,
2692           BnetStrerror(sd));
2693   } else {
2694     Jmsg3(jcr, M_FATAL, 0, _("Bad response to %s command. Wanted %s, got %s\n"),
2695           cmd, resp, sd->msg);
2696   }
2697   return false;
2698 }
2699 } /* namespace filedaemon */
2700