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