1 /*
2    BAREOS® - Backup Archiving REcovery Open Sourced
3 
4    Copyright (C) 2007-2011 Free Software Foundation Europe e.V.
5    Copyright (C) 2011-2012 Planets Communications B.V.
6    Copyright (C) 2013-2020 Bareos GmbH & Co. KG
7 
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version three of the GNU Affero General Public
10    License as published by the Free Software Foundation, which is
11    listed 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 2007
25  */
26 
27 /**
28  * @file
29  * Bareos pluginloader
30  */
31 #include "include/bareos.h"
32 #include "stored/stored.h"
33 #include "stored/stored_globals.h"
34 #include "stored/device_control_record.h"
35 #include "stored/jcr_private.h"
36 #include "sd_plugins.h"
37 #include "lib/crypto_cache.h"
38 #include "stored/sd_stats.h"
39 #include "lib/edit.h"
40 #include "include/jcr.h"
41 
42 namespace storagedaemon {
43 
44 const int debuglevel = 250;
45 #ifdef HAVE_WIN32
46 const char* plugin_type = "-sd.dll";
47 #else
48 const char* plugin_type = "-sd.so";
49 #endif
50 static alist* sd_plugin_list = NULL;
51 
52 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
53 
54 /* Forward referenced functions */
55 static bRC bareosGetValue(PluginContext* ctx, bsdrVariable var, void* value);
56 static bRC bareosSetValue(PluginContext* ctx, bsdwVariable var, void* value);
57 static bRC bareosRegisterEvents(PluginContext* ctx, int nr_events, ...);
58 static bRC bareosUnRegisterEvents(PluginContext* ctx, int nr_events, ...);
59 static bRC bareosGetInstanceCount(PluginContext* ctx, int* ret);
60 static bRC bareosJobMsg(PluginContext* ctx,
61                         const char* file,
62                         int line,
63                         int type,
64                         utime_t mtime,
65                         const char* fmt,
66                         ...);
67 static bRC bareosDebugMsg(PluginContext* ctx,
68                           const char* file,
69                           int line,
70                           int level,
71                           const char* fmt,
72                           ...);
73 static char* bareosEditDeviceCodes(DeviceControlRecord* dcr,
74                                    POOLMEM*& omsg,
75                                    const char* imsg,
76                                    const char* cmd);
77 static char* bareosLookupCryptoKey(const char* VolumeName);
78 static bool bareosUpdateVolumeInfo(DeviceControlRecord* dcr);
79 static void bareosUpdateTapeAlert(DeviceControlRecord* dcr, uint64_t flags);
80 static DeviceRecord* bareosNewRecord(bool with_data);
81 static void bareosCopyRecordState(DeviceRecord* dst, DeviceRecord* src);
82 static void bareosFreeRecord(DeviceRecord* rec);
83 static bool IsPluginCompatible(Plugin* plugin);
84 
85 /* Bareos info */
86 static PluginApiDefinition bareos_plugin_interface_version
87     = {sizeof(PluginFunctions), SD_PLUGIN_INTERFACE_VERSION};
88 
89 /* Bareos entry points */
90 static CoreFunctions bareos_core_functions
91     = {sizeof(CoreFunctions),  SD_PLUGIN_INTERFACE_VERSION,
92        bareosRegisterEvents,   bareosUnRegisterEvents,
93        bareosGetInstanceCount, bareosGetValue,
94        bareosSetValue,         bareosJobMsg,
95        bareosDebugMsg,         bareosEditDeviceCodes,
96        bareosLookupCryptoKey,  bareosUpdateVolumeInfo,
97        bareosUpdateTapeAlert,  bareosNewRecord,
98        bareosCopyRecordState,  bareosFreeRecord};
99 
100 /**
101  * Bareos private context
102  */
103 struct b_plugin_ctx {
104   JobControlRecord* jcr;                        /* jcr for plugin */
105   bRC rc;                                       /* last return code */
106   bool disabled;                                /* set if plugin disabled */
107   char events[NbytesForBits(SD_NR_EVENTS + 1)]; /* enabled events bitmask */
108   Plugin* plugin; /* pointer to plugin of which this is an instance off */
109 };
110 
IsEventEnabled(PluginContext * ctx,bSdEventType eventType)111 static inline bool IsEventEnabled(PluginContext* ctx, bSdEventType eventType)
112 {
113   b_plugin_ctx* b_ctx;
114   if (!ctx) { return false; }
115   b_ctx = (b_plugin_ctx*)ctx->core_private_context;
116   if (!b_ctx) { return false; }
117 
118   return BitIsSet(eventType, b_ctx->events);
119 }
120 
IsPluginDisabled(PluginContext * ctx)121 static inline bool IsPluginDisabled(PluginContext* ctx)
122 {
123   b_plugin_ctx* b_ctx;
124   if (!ctx) { return true; }
125   b_ctx = (b_plugin_ctx*)ctx->core_private_context;
126   if (!b_ctx) { return true; }
127   return b_ctx->disabled;
128 }
129 
IsCtxGood(PluginContext * ctx,JobControlRecord * & jcr,b_plugin_ctx * & bctx)130 static bool IsCtxGood(PluginContext* ctx,
131                       JobControlRecord*& jcr,
132                       b_plugin_ctx*& bctx)
133 {
134   if (!ctx) { return false; }
135 
136   bctx = (b_plugin_ctx*)ctx->core_private_context;
137   if (!bctx) { return false; }
138 
139   jcr = bctx->jcr;
140   if (!jcr) { return false; }
141 
142   return true;
143 }
144 
145 /**
146  * Edit codes into ChangerCommand
147  *  %% = %
148  *  %a = Archive device name
149  *  %c = Changer device name
150  *  %D = Diagnostic device name
151  *  %d = Changer drive index
152  *  %f = Client's name
153  *  %j = Job name
154  *  %o = Command
155  *  %s = Slot base 0
156  *  %S = Slot base 1
157  *  %v = Volume name
158  *
159  *
160  *  omsg = edited output message
161  *  imsg = input string containing edit codes (%x)
162  *  cmd = command string (load, unload, ...)
163  */
edit_device_codes(DeviceControlRecord * dcr,POOLMEM * & omsg,const char * imsg,const char * cmd)164 char* edit_device_codes(DeviceControlRecord* dcr,
165                         POOLMEM*& omsg,
166                         const char* imsg,
167                         const char* cmd)
168 {
169   const char* p;
170   const char* str;
171   char ed1[50];
172 
173   *omsg = 0;
174   Dmsg1(1800, "edit_device_codes: %s\n", imsg);
175   for (p = imsg; *p; p++) {
176     if (*p == '%') {
177       switch (*++p) {
178         case '%':
179           str = "%";
180           break;
181         case 'a':
182           str = dcr->dev->archive_name();
183           break;
184         case 'c':
185           str = NPRT(dcr->device_resource->changer_name);
186           break;
187         case 'D':
188           str = NPRT(dcr->device_resource->diag_device_name);
189           break;
190         case 'd':
191           str = edit_int64(dcr->dev->drive_index, ed1);
192           break;
193         case 'o':
194           str = NPRT(cmd);
195           break;
196         case 's':
197           str = edit_int64(dcr->VolCatInfo.Slot - 1, ed1);
198           break;
199         case 'S':
200           str = edit_int64(dcr->VolCatInfo.Slot, ed1);
201           break;
202         case 'j': /* Job name */
203           str = dcr->jcr->Job;
204           break;
205         case 'v':
206           if (dcr->VolCatInfo.VolCatName[0]) {
207             str = dcr->VolCatInfo.VolCatName;
208           } else if (dcr->VolumeName[0]) {
209             str = dcr->VolumeName;
210           } else if (dcr->dev->vol && dcr->dev->vol->vol_name) {
211             str = dcr->dev->vol->vol_name;
212           } else {
213             str = dcr->dev->VolHdr.VolumeName;
214           }
215           break;
216         case 'f':
217           str = NPRT(dcr->jcr->client_name);
218           break;
219         default:
220           ed1[0] = '%';
221           ed1[1] = *p;
222           ed1[2] = 0;
223           str = ed1;
224           break;
225       }
226     } else {
227       ed1[0] = *p;
228       ed1[1] = 0;
229       str = ed1;
230     }
231     Dmsg1(1900, "add_str %s\n", str);
232     PmStrcat(omsg, (char*)str);
233     Dmsg1(1800, "omsg=%s\n", omsg);
234   }
235   Dmsg1(800, "omsg=%s\n", omsg);
236 
237   return omsg;
238 }
239 
trigger_plugin_event(JobControlRecord * jcr,bSdEventType eventType,bSdEvent * event,PluginContext * ctx,void * value,alist * plugin_ctx_list,int * index,bRC * rc)240 static inline bool trigger_plugin_event(JobControlRecord* jcr,
241                                         bSdEventType eventType,
242                                         bSdEvent* event,
243                                         PluginContext* ctx,
244                                         void* value,
245                                         alist* plugin_ctx_list,
246                                         int* index,
247                                         bRC* rc)
248 {
249   bool stop = false;
250 
251   if (!IsEventEnabled(ctx, eventType)) {
252     Dmsg1(debuglevel, "Event %d disabled for this plugin.\n", eventType);
253     goto bail_out;
254   }
255 
256   if (IsPluginDisabled(ctx)) {
257     Dmsg0(debuglevel, "Plugin disabled.\n");
258     goto bail_out;
259   }
260 
261   /*
262    * See if we should care about the return code.
263    */
264   if (rc) {
265     *rc = SdplugFunc(ctx->plugin)->handlePluginEvent(ctx, event, value);
266     switch (*rc) {
267       case bRC_OK:
268         break;
269       case bRC_Stop:
270       case bRC_Error:
271         stop = true;
272         break;
273       case bRC_More:
274         break;
275       case bRC_Term:
276         /*
277          * Request to unload this plugin.
278          * As we remove the plugin from the list of plugins we decrement
279          * the running index value so the next plugin gets triggered as
280          * that moved back a position in the alist.
281          */
282         if (index) {
283           UnloadPlugin(plugin_ctx_list, ctx->plugin, *index);
284           *index = ((*index) - 1);
285         }
286         break;
287       case bRC_Seen:
288         break;
289       case bRC_Core:
290         break;
291       case bRC_Skip:
292         stop = true;
293         break;
294       case bRC_Cancel:
295         break;
296       default:
297         break;
298     }
299   } else {
300     SdplugFunc(ctx->plugin)->handlePluginEvent(ctx, event, value);
301   }
302 
303 bail_out:
304   return stop;
305 }
306 
307 /**
308  * Create a plugin event
309  */
GeneratePluginEvent(JobControlRecord * jcr,bSdEventType eventType,void * value,bool reverse)310 bRC GeneratePluginEvent(JobControlRecord* jcr,
311                         bSdEventType eventType,
312                         void* value,
313                         bool reverse)
314 {
315   int i;
316   bSdEvent event;
317   alist* plugin_ctx_list;
318   bRC rc = bRC_OK;
319 
320   if (!sd_plugin_list) {
321     Dmsg0(debuglevel, "No bplugin_list: GeneratePluginEvent ignored.\n");
322     goto bail_out;
323   }
324 
325   if (!jcr) {
326     Dmsg0(debuglevel, "No jcr: GeneratePluginEvent ignored.\n");
327     goto bail_out;
328   }
329 
330   /*
331    * Return if no plugins loaded
332    */
333   if (!jcr->plugin_ctx_list) {
334     Dmsg0(debuglevel, "No plugin_ctx_list: GeneratePluginEvent ignored.\n");
335     goto bail_out;
336   }
337 
338   plugin_ctx_list = jcr->plugin_ctx_list;
339   event.eventType = eventType;
340 
341   Dmsg2(debuglevel, "sd-plugin_ctx_list=%p JobId=%d\n", plugin_ctx_list,
342         jcr->JobId);
343 
344   /*
345    * See if we need to trigger the loaded plugins in reverse order.
346    */
347   if (reverse) {
348     PluginContext* ctx;
349 
350     foreach_alist_rindex (i, ctx, plugin_ctx_list) {
351       if (trigger_plugin_event(jcr, eventType, &event, ctx, value,
352                                plugin_ctx_list, &i, &rc)) {
353         break;
354       }
355     }
356   } else {
357     PluginContext* ctx;
358 
359     foreach_alist_index (i, ctx, plugin_ctx_list) {
360       if (trigger_plugin_event(jcr, eventType, &event, ctx, value,
361                                plugin_ctx_list, &i, &rc)) {
362         break;
363       }
364     }
365   }
366 
367   if (jcr->IsJobCanceled()) {
368     Dmsg0(debuglevel, "Cancel return from GeneratePluginEvent\n");
369     rc = bRC_Cancel;
370   }
371 
372 bail_out:
373   return rc;
374 }
375 
376 /**
377  * Print to file the plugin info.
378  */
DumpSdPlugin(Plugin * plugin,FILE * fp)379 void DumpSdPlugin(Plugin* plugin, FILE* fp)
380 {
381   PluginInformation* info;
382 
383   if (!plugin) { return; }
384 
385   info = (PluginInformation*)plugin->plugin_information;
386   fprintf(fp, "\tversion=%d\n", info->version);
387   fprintf(fp, "\tdate=%s\n", NPRTB(info->plugin_date));
388   fprintf(fp, "\tmagic=%s\n", NPRTB(info->plugin_magic));
389   fprintf(fp, "\tauthor=%s\n", NPRTB(info->plugin_author));
390   fprintf(fp, "\tlicence=%s\n", NPRTB(info->plugin_license));
391   fprintf(fp, "\tversion=%s\n", NPRTB(info->plugin_version));
392   fprintf(fp, "\tdescription=%s\n", NPRTB(info->plugin_description));
393 }
394 
DumpSdPlugins(FILE * fp)395 static void DumpSdPlugins(FILE* fp) { DumpPlugins(sd_plugin_list, fp); }
396 
397 /**
398  * This entry point is called internally by Bareos to ensure
399  *  that the plugin IO calls come into this code.
400  */
LoadSdPlugins(const char * plugin_dir,alist * plugin_names)401 void LoadSdPlugins(const char* plugin_dir, alist* plugin_names)
402 {
403   Plugin* plugin;
404   int i;
405 
406   Dmsg0(debuglevel, "Load sd plugins\n");
407   if (!plugin_dir) {
408     Dmsg0(debuglevel, "No sd plugin dir!\n");
409     return;
410   }
411   sd_plugin_list = new alist(10, not_owned_by_alist);
412   if (!LoadPlugins((void*)&bareos_plugin_interface_version,
413                    (void*)&bareos_core_functions, sd_plugin_list, plugin_dir,
414                    plugin_names, plugin_type, IsPluginCompatible)) {
415     /*
416      * Either none found, or some error
417      */
418     if (sd_plugin_list->size() == 0) {
419       delete sd_plugin_list;
420       sd_plugin_list = NULL;
421       Dmsg0(debuglevel, "No plugins loaded\n");
422       return;
423     }
424   }
425   /*
426    * Verify that the plugin is acceptable, and print information about it.
427    */
428   foreach_alist_index (i, plugin, sd_plugin_list) {
429     Dmsg1(debuglevel, "Loaded plugin: %s\n", plugin->file);
430   }
431 
432   Dmsg1(debuglevel, "num plugins=%d\n", sd_plugin_list->size());
433   DbgPluginAddHook(DumpSdPlugin);
434   DbgPrintPluginAddHook(DumpSdPlugins);
435 }
436 
UnloadSdPlugins(void)437 void UnloadSdPlugins(void)
438 {
439   UnloadPlugins(sd_plugin_list);
440   delete sd_plugin_list;
441   sd_plugin_list = NULL;
442 }
443 
ListSdPlugins(PoolMem & msg)444 int ListSdPlugins(PoolMem& msg) { return ListPlugins(sd_plugin_list, msg); }
445 
446 /**
447  * Check if a plugin is compatible.  Called by the load_plugin function
448  *  to allow us to verify the plugin.
449  */
IsPluginCompatible(Plugin * plugin)450 static bool IsPluginCompatible(Plugin* plugin)
451 {
452   PluginInformation* info = (PluginInformation*)plugin->plugin_information;
453   Dmsg0(50, "IsPluginCompatible called\n");
454   if (debug_level >= 50) { DumpSdPlugin(plugin, stdin); }
455   if (!bstrcmp(info->plugin_magic, SD_PLUGIN_MAGIC)) {
456     Jmsg(NULL, M_ERROR, 0,
457          _("Plugin magic wrong. Plugin=%s wanted=%s got=%s\n"), plugin->file,
458          SD_PLUGIN_MAGIC, info->plugin_magic);
459     Dmsg3(50, "Plugin magic wrong. Plugin=%s wanted=%s got=%s\n", plugin->file,
460           SD_PLUGIN_MAGIC, info->plugin_magic);
461 
462     return false;
463   }
464   if (info->version != SD_PLUGIN_INTERFACE_VERSION) {
465     Jmsg(NULL, M_ERROR, 0,
466          _("Plugin version incorrect. Plugin=%s wanted=%d got=%d\n"),
467          plugin->file, SD_PLUGIN_INTERFACE_VERSION, info->version);
468     Dmsg3(50, "Plugin version incorrect. Plugin=%s wanted=%d got=%d\n",
469           plugin->file, SD_PLUGIN_INTERFACE_VERSION, info->version);
470     return false;
471   }
472   if (!Bstrcasecmp(info->plugin_license, "Bareos AGPLv3")
473       && !Bstrcasecmp(info->plugin_license, "AGPLv3")) {
474     Jmsg(NULL, M_ERROR, 0,
475          _("Plugin license incompatible. Plugin=%s license=%s\n"), plugin->file,
476          info->plugin_license);
477     Dmsg2(50, "Plugin license incompatible. Plugin=%s license=%s\n",
478           plugin->file, info->plugin_license);
479     return false;
480   }
481   if (info->size != sizeof(PluginInformation)) {
482     Jmsg(NULL, M_ERROR, 0,
483          _("Plugin size incorrect. Plugin=%s wanted=%d got=%d\n"), plugin->file,
484          sizeof(PluginInformation), info->size);
485     return false;
486   }
487 
488   return true;
489 }
490 
491 /**
492  * Instantiate a new plugin instance.
493  */
instantiate_plugin(JobControlRecord * jcr,Plugin * plugin,uint32_t instance)494 static inline PluginContext* instantiate_plugin(JobControlRecord* jcr,
495                                                 Plugin* plugin,
496                                                 uint32_t instance)
497 {
498   PluginContext* ctx;
499   b_plugin_ctx* b_ctx;
500 
501   b_ctx = (b_plugin_ctx*)malloc(sizeof(b_plugin_ctx));
502   memset(b_ctx, 0, sizeof(b_plugin_ctx));
503   b_ctx->jcr = jcr;
504   b_ctx->plugin = plugin;
505 
506   Dmsg2(debuglevel, "Instantiate dir-plugin_ctx_list=%p JobId=%d\n",
507         jcr->plugin_ctx_list, jcr->JobId);
508 
509   ctx = (PluginContext*)malloc(sizeof(PluginContext));
510   ctx->instance = instance;
511   ctx->plugin = plugin;
512   ctx->core_private_context = (void*)b_ctx;
513   ctx->plugin_private_context = NULL;
514 
515   jcr->plugin_ctx_list->append(ctx);
516 
517   if (SdplugFunc(plugin)->newPlugin(ctx) != bRC_OK) { b_ctx->disabled = true; }
518 
519   return ctx;
520 }
521 
522 /**
523  * Send a bSdEventNewPluginOptions event to all plugins configured in
524  * jcr->impl_->plugin_options.
525  */
DispatchNewPluginOptions(JobControlRecord * jcr)526 void DispatchNewPluginOptions(JobControlRecord* jcr)
527 {
528   int i, j, len;
529   Plugin* plugin;
530   PluginContext* ctx = nullptr;
531   uint32_t instance;
532   bSdEvent event;
533   bSdEventType eventType;
534   char *bp, *plugin_name, *option;
535   const char* plugin_options;
536   PoolMem priv_plugin_options(PM_MESSAGE);
537 
538   if (!sd_plugin_list || sd_plugin_list->empty()) { return; }
539 
540   if (jcr->impl->plugin_options && jcr->impl->plugin_options->size()) {
541     eventType = bSdEventNewPluginOptions;
542     event.eventType = eventType;
543 
544     foreach_alist_index (i, plugin_options, jcr->impl->plugin_options) {
545       /*
546        * Make a private copy of plugin options.
547        */
548       PmStrcpy(priv_plugin_options, plugin_options);
549 
550       plugin_name = priv_plugin_options.c_str();
551       if (!(bp = strchr(plugin_name, ':'))) {
552         Jmsg(NULL, M_ERROR, 0,
553              _("Illegal SD plugin options encountered, %s skipping\n"),
554              priv_plugin_options.c_str());
555         continue;
556       }
557       *bp++ = '\0';
558 
559       /*
560        * See if there is any instance named in the options string.
561        */
562       instance = 0;
563       option = bp;
564       while (option) {
565         bp = strchr(bp, ':');
566         if (bp) { *bp++ = '\0'; }
567 
568         if (bstrncasecmp(option, "instance=", 9)) {
569           instance = str_to_int64(option + 9);
570           break;
571         }
572 
573         option = bp;
574       }
575 
576       if (instance < LOWEST_PLUGIN_INSTANCE
577           || instance > HIGHEST_PLUGIN_INSTANCE) {
578         Jmsg(NULL, M_ERROR, 0,
579              _("Illegal SD plugin options encountered, %s instance %d "
580                "skipping\n"),
581              plugin_options, instance);
582         continue;
583       }
584 
585       len = strlen(plugin_name);
586 
587       /*
588        * See if this plugin options are for an already instantiated plugin
589        * instance.
590        */
591       if (jcr->plugin_ctx_list) {
592         foreach_alist (ctx, jcr->plugin_ctx_list) {
593           if (ctx->instance == instance && ctx->plugin->file_len == len
594               && bstrncasecmp(ctx->plugin->file, plugin_name, len)) {
595             break;
596           }
597         }
598 
599         /*
600          * Found a context in the previous loop ?
601          */
602         if (!ctx) {
603           foreach_alist_index (j, plugin, sd_plugin_list) {
604             if (plugin->file_len == len
605                 && bstrncasecmp(plugin->file, plugin_name, len)) {
606               ctx = instantiate_plugin(jcr, plugin, instance);
607               break;
608             }
609           }
610         }
611 
612         if (ctx) {
613           trigger_plugin_event(jcr, eventType, &event, ctx,
614                                (void*)plugin_options, NULL, NULL, NULL);
615         }
616       }
617     }
618   }
619 }
620 
621 /**
622  * Create a new instance of each plugin for this Job
623  */
NewPlugins(JobControlRecord * jcr)624 void NewPlugins(JobControlRecord* jcr)
625 {
626   Plugin* plugin;
627   int i, num;
628 
629   Dmsg0(debuglevel, "=== enter NewPlugins ===\n");
630   if (!sd_plugin_list) {
631     Dmsg0(debuglevel, "No sd plugin list!\n");
632     return;
633   }
634   if (jcr->IsJobCanceled()) { return; }
635   /*
636    * If plugins already loaded, just return
637    */
638   if (jcr->plugin_ctx_list) { return; }
639 
640   num = sd_plugin_list->size();
641   Dmsg1(debuglevel, "sd-plugin-list size=%d\n", num);
642   if (num == 0) { return; }
643 
644   jcr->plugin_ctx_list = new alist(10, owned_by_alist);
645   foreach_alist_index (i, plugin, sd_plugin_list) {
646     /*
647      * Start a new instance of each plugin
648      */
649     instantiate_plugin(jcr, plugin, 0);
650   }
651 }
652 
653 /**
654  * Free the plugin instances for this Job
655  */
FreePlugins(JobControlRecord * jcr)656 void FreePlugins(JobControlRecord* jcr)
657 {
658   PluginContext* ctx = nullptr;
659 
660   if (!sd_plugin_list || !jcr->plugin_ctx_list) { return; }
661 
662   Dmsg2(debuglevel, "Free instance dir-plugin_ctx_list=%p JobId=%d\n",
663         jcr->plugin_ctx_list, jcr->JobId);
664   foreach_alist (ctx, jcr->plugin_ctx_list) {
665     /*
666      * Free the plugin instance
667      */
668     SdplugFunc(ctx->plugin)->freePlugin(ctx);
669     free(ctx->core_private_context); /* Free BAREOS private context */
670   }
671 
672   delete jcr->plugin_ctx_list;
673   jcr->plugin_ctx_list = NULL;
674 }
675 
676 /* ==============================================================
677  *
678  * Callbacks from the plugin
679  *
680  * ==============================================================
681  */
bareosGetValue(PluginContext * ctx,bsdrVariable var,void * value)682 static bRC bareosGetValue(PluginContext* ctx, bsdrVariable var, void* value)
683 {
684   JobControlRecord* jcr = NULL;
685   bRC retval = bRC_OK;
686 
687   if (!value) { return bRC_Error; }
688 
689   switch (var) { /* General variables, no need of ctx */
690     case bsdVarCompatible:
691       *((bool*)value) = me->compatible;
692       Dmsg1(debuglevel, "sd-plugin: return bsdVarCompatible=%s\n",
693             (me->compatible) ? "true" : "false");
694       break;
695     case bsdVarPluginDir:
696       *((char**)value) = me->plugin_directory;
697       Dmsg1(debuglevel, "sd-plugin: return bsdVarPluginDir=%s\n",
698             me->plugin_directory);
699       break;
700     default:
701       if (!ctx) { return bRC_Error; }
702 
703       jcr = ((b_plugin_ctx*)ctx->core_private_context)->jcr;
704       if (!jcr) { return bRC_Error; }
705       break;
706   }
707 
708   if (jcr) {
709     switch (var) {
710       case bsdVarJob:
711         *((char**)value) = jcr->impl->job_name;
712         Dmsg1(debuglevel, "sd-plugin: return bsdVarJobName=%s\n",
713               NPRT(*((char**)value)));
714         break;
715       case bsdVarLevel:
716         *((int*)value) = jcr->getJobLevel();
717         Dmsg1(debuglevel, "sd-plugin: return bsdVarLevel=%c\n",
718               jcr->getJobLevel());
719         break;
720       case bsdVarType:
721         *((int*)value) = jcr->getJobType();
722         Dmsg1(debuglevel, "sd-plugin: return bsdVarType=%c\n",
723               jcr->getJobType());
724         break;
725       case bsdVarJobId:
726         *((int*)value) = jcr->JobId;
727         Dmsg1(debuglevel, "sd-plugin: return bsdVarJobId=%d\n", jcr->JobId);
728         break;
729       case bsdVarClient:
730         *((char**)value) = jcr->client_name;
731         Dmsg1(debuglevel, "sd-plugin: return bsdVarClient=%s\n",
732               NPRT(*((char**)value)));
733         break;
734       case bsdVarPool:
735         if (jcr->impl->dcr) {
736           *((char**)value) = jcr->impl->dcr->pool_name;
737           Dmsg1(debuglevel, "sd-plugin: return bsdVarPool=%s\n",
738                 NPRT(*((char**)value)));
739         } else {
740           retval = bRC_Error;
741         }
742         break;
743       case bsdVarPoolType:
744         if (jcr->impl->dcr) {
745           *((char**)value) = jcr->impl->dcr->pool_type;
746           Dmsg1(debuglevel, "sd-plugin: return bsdVarPoolType=%s\n",
747                 NPRT(*((char**)value)));
748         } else {
749           retval = bRC_Error;
750         }
751         break;
752       case bsdVarStorage:
753         if (jcr->impl->dcr && jcr->impl->dcr->device_resource) {
754           *((char**)value) = jcr->impl->dcr->device_resource->resource_name_;
755           Dmsg1(debuglevel, "sd-plugin: return bsdVarStorage=%s\n",
756                 NPRT(*((char**)value)));
757         } else {
758           retval = bRC_Error;
759         }
760         break;
761       case bsdVarMediaType:
762         if (jcr->impl->dcr) {
763           *((char**)value) = jcr->impl->dcr->media_type;
764           Dmsg1(debuglevel, "sd-plugin: return bsdVarMediaType=%s\n",
765                 NPRT(*((char**)value)));
766         } else {
767           retval = bRC_Error;
768         }
769         break;
770       case bsdVarJobName:
771         *((char**)value) = jcr->Job;
772         Dmsg1(debuglevel, "sd-plugin: return bsdVarJobName=%s\n",
773               NPRT(*((char**)value)));
774         break;
775       case bsdVarJobStatus:
776         *((int*)value) = jcr->JobStatus;
777         Dmsg1(debuglevel, "sd-plugin: return bsdVarJobStatus=%c\n",
778               jcr->JobStatus);
779         break;
780       case bsdVarVolumeName:
781         if (jcr->impl->dcr) {
782           *((char**)value) = jcr->impl->dcr->VolumeName;
783           Dmsg1(debuglevel, "sd-plugin: return bsdVarVolumeName=%s\n",
784                 NPRT(*((char**)value)));
785         } else {
786           retval = bRC_Error;
787         }
788         Dmsg1(debuglevel, "sd-plugin: return bsdVarVolumeName=%s\n",
789               jcr->VolumeName);
790         break;
791       case bsdVarJobErrors:
792         *((int*)value) = jcr->JobErrors;
793         Dmsg1(debuglevel, "sd-plugin: return bsdVarJobErrors=%d\n",
794               jcr->JobErrors);
795         break;
796       case bsdVarJobFiles:
797         *((int*)value) = jcr->JobFiles;
798         Dmsg1(debuglevel, "sd-plugin: return bsdVarJobFiles=%d\n",
799               jcr->JobFiles);
800         break;
801       case bsdVarJobBytes:
802         *((uint64_t*)value) = jcr->JobBytes;
803         Dmsg1(debuglevel, "sd-plugin: return bsdVarJobBytes=%d\n",
804               jcr->JobBytes);
805         break;
806       default:
807         break;
808     }
809   }
810 
811   return retval;
812 }
813 
bareosSetValue(PluginContext * ctx,bsdwVariable var,void * value)814 static bRC bareosSetValue(PluginContext* ctx, bsdwVariable var, void* value)
815 {
816   JobControlRecord* jcr;
817   if (!value || !ctx) { return bRC_Error; }
818 
819   jcr = ((b_plugin_ctx*)ctx->core_private_context)->jcr;
820   if (!jcr) { return bRC_Error; }
821 
822   Dmsg1(debuglevel, "sd-plugin: bareosSetValue var=%d\n", var);
823   switch (var) {
824     case bsdwVarVolumeName:
825       PmStrcpy(jcr->VolumeName, ((char*)value));
826       break;
827     case bsdwVarPriority:
828       jcr->JobPriority = *((int*)value);
829       break;
830     case bsdwVarJobLevel:
831       jcr->setJobLevel(*((int*)value));
832       break;
833     default:
834       break;
835   }
836 
837   return bRC_OK;
838 }
839 
bareosRegisterEvents(PluginContext * ctx,int nr_events,...)840 static bRC bareosRegisterEvents(PluginContext* ctx, int nr_events, ...)
841 {
842   int i;
843   va_list args;
844   uint32_t event;
845   b_plugin_ctx* b_ctx;
846 
847   if (!ctx) { return bRC_Error; }
848   b_ctx = (b_plugin_ctx*)ctx->core_private_context;
849   va_start(args, nr_events);
850   for (i = 0; i < nr_events; i++) {
851     event = va_arg(args, uint32_t);
852     Dmsg1(debuglevel, "sd-plugin: Plugin registered event=%u\n", event);
853     SetBit(event, b_ctx->events);
854   }
855   va_end(args);
856   return bRC_OK;
857 }
858 
bareosUnRegisterEvents(PluginContext * ctx,int nr_events,...)859 static bRC bareosUnRegisterEvents(PluginContext* ctx, int nr_events, ...)
860 {
861   int i;
862   va_list args;
863   uint32_t event;
864   b_plugin_ctx* b_ctx;
865 
866   if (!ctx) { return bRC_Error; }
867   b_ctx = (b_plugin_ctx*)ctx->core_private_context;
868   va_start(args, nr_events);
869   for (i = 0; i < nr_events; i++) {
870     event = va_arg(args, uint32_t);
871     Dmsg1(debuglevel, "sd-plugin: Plugin unregistered event=%u\n", event);
872     ClearBit(event, b_ctx->events);
873   }
874   va_end(args);
875   return bRC_OK;
876 }
877 
bareosGetInstanceCount(PluginContext * ctx,int * ret)878 static bRC bareosGetInstanceCount(PluginContext* ctx, int* ret)
879 {
880   int cnt;
881   JobControlRecord *jcr, *njcr;
882   PluginContext* nctx;
883   b_plugin_ctx* bctx;
884   bRC retval = bRC_Error;
885 
886   if (!IsCtxGood(ctx, jcr, bctx)) { goto bail_out; }
887 
888   P(mutex);
889 
890   cnt = 0;
891   foreach_jcr (njcr) {
892     if (jcr->plugin_ctx_list) {
893       foreach_alist (nctx, jcr->plugin_ctx_list) {
894         if (nctx->plugin == bctx->plugin) { cnt++; }
895       }
896     }
897   }
898   endeach_jcr(njcr);
899 
900   V(mutex);
901 
902   *ret = cnt;
903   retval = bRC_OK;
904 
905 bail_out:
906   return retval;
907 }
908 
bareosJobMsg(PluginContext * ctx,const char * file,int line,int type,utime_t mtime,const char * fmt,...)909 static bRC bareosJobMsg(PluginContext* ctx,
910                         const char* file,
911                         int line,
912                         int type,
913                         utime_t mtime,
914                         const char* fmt,
915                         ...)
916 {
917   JobControlRecord* jcr;
918   va_list arg_ptr;
919   PoolMem buffer(PM_MESSAGE);
920 
921   if (ctx) {
922     jcr = ((b_plugin_ctx*)ctx->core_private_context)->jcr;
923   } else {
924     jcr = NULL;
925   }
926 
927   va_start(arg_ptr, fmt);
928   buffer.Bvsprintf(fmt, arg_ptr);
929   va_end(arg_ptr);
930   Jmsg(jcr, type, mtime, "%s", buffer.c_str());
931 
932   return bRC_OK;
933 }
934 
bareosDebugMsg(PluginContext * ctx,const char * file,int line,int level,const char * fmt,...)935 static bRC bareosDebugMsg(PluginContext* ctx,
936                           const char* file,
937                           int line,
938                           int level,
939                           const char* fmt,
940                           ...)
941 {
942   va_list arg_ptr;
943   PoolMem buffer(PM_MESSAGE);
944 
945   va_start(arg_ptr, fmt);
946   buffer.Bvsprintf(fmt, arg_ptr);
947   va_end(arg_ptr);
948   d_msg(file, line, level, "%s", buffer.c_str());
949 
950   return bRC_OK;
951 }
952 
bareosEditDeviceCodes(DeviceControlRecord * dcr,POOLMEM * & omsg,const char * imsg,const char * cmd)953 static char* bareosEditDeviceCodes(DeviceControlRecord* dcr,
954                                    POOLMEM*& omsg,
955                                    const char* imsg,
956                                    const char* cmd)
957 {
958   return edit_device_codes(dcr, omsg, imsg, cmd);
959 }
960 
bareosLookupCryptoKey(const char * VolumeName)961 static char* bareosLookupCryptoKey(const char* VolumeName)
962 {
963   return lookup_crypto_cache_entry(VolumeName);
964 }
965 
bareosUpdateVolumeInfo(DeviceControlRecord * dcr)966 static bool bareosUpdateVolumeInfo(DeviceControlRecord* dcr)
967 {
968   return dcr->DirGetVolumeInfo(GET_VOL_INFO_FOR_READ);
969 }
970 
bareosUpdateTapeAlert(DeviceControlRecord * dcr,uint64_t flags)971 static void bareosUpdateTapeAlert(DeviceControlRecord* dcr, uint64_t flags)
972 {
973   utime_t now;
974   now = (utime_t)time(NULL);
975 
976   UpdateDeviceTapealert(dcr->device_resource->resource_name_, flags, now);
977 }
978 
bareosNewRecord(bool with_data)979 static DeviceRecord* bareosNewRecord(bool with_data)
980 {
981   return new_record(with_data);
982 }
983 
bareosCopyRecordState(DeviceRecord * dst,DeviceRecord * src)984 static void bareosCopyRecordState(DeviceRecord* dst, DeviceRecord* src)
985 {
986   CopyRecordState(dst, src);
987 }
988 
bareosFreeRecord(DeviceRecord * rec)989 static void bareosFreeRecord(DeviceRecord* rec) { FreeRecord(rec); }
990 
991 } /* namespace storagedaemon */
992