1 /*
2    BAREOS® - Backup Archiving REcovery Open Sourced
3 
4    Copyright (C) 2006-2012 Free Software Foundation Europe e.V.
5    Copyright (C) 2011-2012 Planets Communications B.V.
6    Copyright (C) 2013-2020 Bareos GmbH & Co. KG
7 
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version three of the GNU Affero General Public
10    License as published by the Free Software Foundation and included
11    in the file LICENSE.
12 
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    Affero General Public License for more details.
17 
18    You should have received a copy of the GNU Affero General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22 */
23 
24 /*
25  * Contributed in 2012 by Inteos sp. z o.o.
26  */
27 
28 /**
29  * Utility tool display various information about Bareos plugin,
30  * including but not limited to:
31  * - Name and Author of the plugin
32  * - Plugin License
33  * - Description
34  * - API version
35  * - Enabled functions, etc.
36  */
37 #include "include/bareos.h"
38 #include "filed/fd_plugins.h"
39 #include "dird/dir_plugins.h"
40 #include "stored/sd_plugins.h"
41 #include "assert_macro.h"
42 #ifndef __WIN32__
43 #  include <dlfcn.h>
44 #endif
45 #ifndef PATH_MAX
46 #  define PATH_MAX 4096
47 #endif
48 
49 extern "C" {
50 typedef int (*loadPlugin)(void* bareos_plugin_interface_version,
51                           void* bareos_core_functions,
52                           void** plugin_information,
53                           void** plugin_functions);
54 typedef int (*unloadPlugin)(void);
55 }
56 #define DEFAULT_API_VERSION 1
57 
58 enum plugintype
59 {
60   DIRPLUGIN,
61   FDPLUGIN,
62   SDPLUGIN,
63   ERRORPLUGIN
64 };
65 
66 /*
67  * PluginFunctions
68  */
69 typedef union _plugfuncs plugfuncs;
70 union _plugfuncs {
71   directordaemon::PluginFunctions pdirfuncs;
72   filedaemon::PluginFunctions pfdfuncs;
73   storagedaemon::PluginFunctions psdfuncs;
74 };
75 
76 /*
77  * CoreFunctions
78  */
79 typedef struct _bareosfuncs bareosfuncs;
80 struct _bareosfuncs {
81   uint32_t size;
82   uint32_t version;
83   int (*registerBareosEvents)(void* ctx, ...);
84   int (*getBareosValue)(void* ctx, int var, void* value);
85   int (*setBareosValue)(void* ctx, int var, void* value);
86   int (*JobMessage)(void* ctx,
87                     const char* file,
88                     int line,
89                     int type,
90                     int64_t mtime,
91                     const char* fmt,
92                     ...);
93   int (*DebugMessage)(void* ctx,
94                       const char* file,
95                       int line,
96                       int level,
97                       const char* fmt,
98                       ...);
99   void* (*bareosMalloc)(void* ctx, const char* file, int line, size_t size);
100   void (*bareosFree)(void* ctx, const char* file, int line, void* mem);
101 };
102 
103 /*
104  * PluginApiDefinition
105  */
106 typedef union _bareosinfos bareosinfos;
107 union _bareosinfos {
108   directordaemon::PluginApiDefinition bdirinfo;
109   filedaemon::PluginApiDefinition bfdinfo;
110   storagedaemon::PluginApiDefinition bsdinfo;
111 };
112 
113 typedef struct _progdata progdata;
114 struct _progdata {
115   bool verbose;
116   bool listinfo;
117   bool listfunc;
118   char* pluginfile;
119   void* pluginhandle;
120   int bapiversion;
121   int bplugtype;
122   gen_pluginInfo* plugin_information;
123   plugfuncs* plugin_functions;
124 };
125 
126 /* memory allocation/deallocation */
127 #define MALLOC(size) (char*)malloc(size);
128 
129 #define ASSERT_MEMORY(m)                         \
130   if (m == NULL) {                               \
131     printf("Error: memory allocation error!\n"); \
132     exit(10);                                    \
133   }
134 
135 #define FREE(ptr)    \
136   if (ptr != NULL) { \
137     free(ptr);       \
138     ptr = NULL;      \
139   }
140 
registerBareosEvents(void * ctx,...)141 int registerBareosEvents(void* ctx, ...) { return 0; };
142 
getBareosValue(void * ctx,int var,void * value)143 int getBareosValue(void* ctx, int var, void* value) { return 0; };
144 
setBareosValue(void * ctx,int var,void * value)145 int setBareosValue(void* ctx, int var, void* value) { return 0; };
146 
DebugMessage(void * ctx,const char * file,int line,int level,const char * fmt,...)147 int DebugMessage(void* ctx,
148                  const char* file,
149                  int line,
150                  int level,
151                  const char* fmt,
152                  ...)
153 {
154 #ifdef DEBUGMSG
155   printf("DG: %s:%d %s\n", file, line, fmt);
156 #endif
157   return 0;
158 };
159 
JobMessage(void * ctx,const char * file,int line,int type,int64_t mtime,const char * fmt,...)160 int JobMessage(void* ctx,
161                const char* file,
162                int line,
163                int type,
164                int64_t mtime,
165                const char* fmt,
166                ...)
167 {
168 #ifdef DEBUGMSG
169   printf("JM: %s:%d <%d> %s\n", file, line, type, fmt);
170 #endif
171   return 0;
172 };
173 
bareosMalloc(void * ctx,const char * file,int line,size_t size)174 void* bareosMalloc(void* ctx, const char* file, int line, size_t size)
175 {
176   return MALLOC(size);
177 };
178 
bareosFree(void * ctx,const char * file,int line,void * mem)179 void bareosFree(void* ctx, const char* file, int line, void* mem)
180 {
181   FREE(mem);
182 };
183 
184 /*
185  * displays a short help
186  */
PrintHelp(int argc,char * argv[])187 void PrintHelp(int argc, char* argv[])
188 {
189   printf(
190       "\n"
191       "Usage: bpluginfo [options] <plugin_file.so>\n"
192       "       -v          verbose\n"
193       "       -i          list plugin header information only (default)\n"
194       "       -f          list plugin functions information only\n"
195       "       -a <api>    bareos api version (default %d)\n"
196       "       -h          help screen\n"
197       "\n",
198       DEFAULT_API_VERSION);
199 }
200 
201 /* allocates and resets a main program data variable */
allocpdata(void)202 progdata* allocpdata(void)
203 {
204   progdata* pdata;
205 
206   pdata = (progdata*)malloc(sizeof(progdata));
207   ASSERT_MEMORY(pdata);
208   memset(pdata, 0, sizeof(progdata));
209 
210   return pdata;
211 }
212 
213 /* releases all allocated program data resources */
Freepdata(progdata * pdata)214 void Freepdata(progdata* pdata)
215 {
216   if (pdata->pluginfile) { FREE(pdata->pluginfile); }
217   FREE(pdata);
218 }
219 
220 /*
221  * parse execution arguments and fills required pdata structure fields
222  *
223  * input:
224  *    pdata - pointer to program data structure
225  *    argc, argv - execution envinroment variables
226  * output:
227  *    pdata - required structure fields
228  *
229  * supported options:
230  * -v    verbose flag
231  * -i    list plugin header info only (default)
232  * -f    list implemented functions only
233  * -a    bareos api version (default 1)
234  * -h    help screen
235  */
ParseArgs(progdata * pdata,int argc,char * argv[])236 void ParseArgs(progdata* pdata, int argc, char* argv[])
237 {
238   int ch;
239   char* dirtmp;
240   char* progdir;
241 
242   while ((ch = getopt(argc, argv, "a:fiv")) != -1) {
243     switch (ch) {
244       case 'a':
245         pdata->bapiversion = atoi(optarg);
246         break;
247 
248       case 'f':
249         pdata->listfunc = true;
250         break;
251 
252       case 'i':
253         pdata->listinfo = true;
254         break;
255 
256       case 'v':
257         pdata->verbose = true;
258         break;
259 
260       case '?':
261       default:
262         PrintHelp(argc, argv);
263         exit(0);
264     }
265   }
266   argc -= optind;
267   argv += optind;
268 
269   if (argc < 1) {
270     PrintHelp(argc, argv);
271     exit(0);
272   }
273 
274   if (!pdata->pluginfile) {
275     if (argv[0][0] != '/') {
276       dirtmp = MALLOC(PATH_MAX);
277       ASSERT_MEMORY(dirtmp);
278       progdir = MALLOC(PATH_MAX);
279       ASSERT_MEMORY(progdir);
280       dirtmp = getcwd(dirtmp, PATH_MAX);
281 
282       strcat(dirtmp, "/");
283       strcat(dirtmp, argv[0]);
284 
285       if (realpath(dirtmp, progdir) == NULL) {
286         /*
287          * Error in resolving path
288          */
289         FREE(progdir);
290         progdir = strdup(argv[0]);
291       }
292       pdata->pluginfile = strdup(progdir);
293       FREE(dirtmp);
294       FREE(progdir);
295     } else {
296       pdata->pluginfile = strdup(argv[0]);
297     }
298   }
299 }
300 
301 /*
302  * checks a plugin type based on a plugin magic string
303  *
304  * input:
305  *    pdata - program data with plugin info structure
306  * output:
307  *    int - enum plugintype
308  */
Getplugintype(progdata * pdata)309 int Getplugintype(progdata* pdata)
310 {
311   ASSERT_NVAL_RET_V(pdata, ERRORPLUGIN);
312 
313   gen_pluginInfo* plugin_information = pdata->plugin_information;
314 
315   ASSERT_NVAL_RET_V(plugin_information, ERRORPLUGIN);
316 
317   if (plugin_information->plugin_magic
318       && bstrcmp(plugin_information->plugin_magic, DIR_PLUGIN_MAGIC)) {
319     return DIRPLUGIN;
320   } else {
321     if (plugin_information->plugin_magic
322         && bstrcmp(plugin_information->plugin_magic, FD_PLUGIN_MAGIC)) {
323       return FDPLUGIN;
324     } else {
325       if (plugin_information->plugin_magic
326           && bstrcmp(plugin_information->plugin_magic, SD_PLUGIN_MAGIC)) {
327         return SDPLUGIN;
328       } else {
329         return ERRORPLUGIN;
330       }
331     }
332   }
333 }
334 
335 /*
336  * prints any available information about a plugin
337  *
338  * input:
339  *    pdata - program data with plugin info structure
340  * output:
341  *    printed info
342  */
DumpPluginfo(progdata * pdata)343 void DumpPluginfo(progdata* pdata)
344 {
345   ASSERT_NVAL_RET(pdata);
346 
347   gen_pluginInfo* plugin_information = pdata->plugin_information;
348 
349   ASSERT_NVAL_RET(plugin_information);
350 
351   plugfuncs* plugin_functions = pdata->plugin_functions;
352 
353   ASSERT_NVAL_RET(plugin_functions);
354 
355   switch (pdata->bplugtype) {
356     case DIRPLUGIN:
357       printf("\nPlugin type:\t\tBareos Director plugin\n");
358       break;
359     case FDPLUGIN:
360       printf("\nPlugin type:\t\tBareos File Daemon plugin\n");
361       break;
362     case SDPLUGIN:
363       printf("\nPlugin type:\t\tBareos Storage plugin\n");
364       break;
365     default:
366       printf("\nUnknown plugin type or other Error\n\n");
367       return;
368   }
369 
370   if (pdata->verbose) {
371     printf("Plugin magic:\t\t%s\n", NPRT(plugin_information->plugin_magic));
372   }
373   printf("Plugin version:\t\t%s\n", plugin_information->plugin_version);
374   printf("Plugin release date:\t%s\n", NPRT(plugin_information->plugin_date));
375   printf("Plugin author:\t\t%s\n", NPRT(plugin_information->plugin_author));
376   printf("Plugin licence:\t\t%s\n", NPRT(plugin_information->plugin_license));
377   printf("Plugin description:\t%s\n",
378          NPRT(plugin_information->plugin_description));
379   printf("Plugin API version:\t%d\n", plugin_information->version);
380   if (plugin_information->plugin_usage) {
381     printf("Plugin usage:\n%s\n", plugin_information->plugin_usage);
382   }
383 }
384 
385 /*
386  * prints any available information about plugin' functions
387  *
388  * input:
389  *    pdata - program data with plugin info structure
390  * output:
391  *    printed info
392  */
DumpPlugfuncs(progdata * pdata)393 void DumpPlugfuncs(progdata* pdata)
394 {
395   ASSERT_NVAL_RET(pdata);
396 
397   plugfuncs* plugin_functions = pdata->plugin_functions;
398 
399   ASSERT_NVAL_RET(plugin_functions);
400 
401   printf("\nPlugin functions:\n");
402 
403   switch (pdata->bplugtype) {
404     case DIRPLUGIN:
405       if (pdata->verbose) {
406         if (plugin_functions->pdirfuncs.newPlugin) { printf(" newPlugin()\n"); }
407         if (plugin_functions->pdirfuncs.freePlugin) {
408           printf(" freePlugin()\n");
409         }
410       }
411       if (plugin_functions->pdirfuncs.getPluginValue) {
412         printf(" getPluginValue()\n");
413       }
414       if (plugin_functions->pdirfuncs.setPluginValue) {
415         printf(" setPluginValue()\n");
416       }
417       if (plugin_functions->pdirfuncs.handlePluginEvent) {
418         printf(" handlePluginEvent()\n");
419       }
420       break;
421     case FDPLUGIN:
422       if (pdata->verbose) {
423         if (plugin_functions->pfdfuncs.newPlugin) { printf(" newPlugin()\n"); }
424         if (plugin_functions->pfdfuncs.freePlugin) {
425           printf(" freePlugin()\n");
426         }
427       }
428       if (plugin_functions->pfdfuncs.getPluginValue) {
429         printf(" getPluginValue()\n");
430       }
431       if (plugin_functions->pfdfuncs.setPluginValue) {
432         printf(" setPluginValue()\n");
433       }
434       if (plugin_functions->pfdfuncs.handlePluginEvent) {
435         printf(" handlePluginEvent()\n");
436       }
437       if (plugin_functions->pfdfuncs.startBackupFile) {
438         printf(" startBackupFile()\n");
439       }
440       if (plugin_functions->pfdfuncs.endBackupFile) {
441         printf(" endBackupFile()\n");
442       }
443       if (plugin_functions->pfdfuncs.startRestoreFile) {
444         printf(" startRestoreFile()\n");
445       }
446       if (plugin_functions->pfdfuncs.endRestoreFile) {
447         printf(" endRestoreFile()\n");
448       }
449       if (plugin_functions->pfdfuncs.pluginIO) { printf(" pluginIO()\n"); }
450       if (plugin_functions->pfdfuncs.createFile) { printf(" createFile()\n"); }
451       if (plugin_functions->pfdfuncs.setFileAttributes) {
452         printf(" setFileAttributes()\n");
453       }
454       if (plugin_functions->pfdfuncs.checkFile) { printf(" checkFile()\n"); }
455       break;
456     case SDPLUGIN:
457       if (pdata->verbose) {
458         if (plugin_functions->psdfuncs.newPlugin) { printf(" newPlugin()\n"); }
459         if (plugin_functions->psdfuncs.freePlugin) {
460           printf(" freePlugin()\n");
461         }
462       }
463       if (plugin_functions->psdfuncs.getPluginValue) {
464         printf(" getPluginValue()\n");
465       }
466       if (plugin_functions->psdfuncs.setPluginValue) {
467         printf(" setPluginValue()\n");
468       }
469       if (plugin_functions->psdfuncs.handlePluginEvent) {
470         printf(" handlePluginEvent()\n");
471       }
472       break;
473     default:
474       printf("\nUnknown plugin type or other Error\n\n");
475   }
476 }
477 
478 /*
479  * input parameters:
480  *    argv[0] [options] <plugin_filename.so>
481  *
482  * exit codes:
483  *    0 - success
484  *    1 - cannot load a plugin
485  *    2 - cannot find a loadPlugin function
486  *    3 - cannot find an unloadPlugin function
487  *    10 - not enough memory
488  */
main(int argc,char * argv[])489 int main(int argc, char* argv[])
490 {
491   progdata* pdata;
492   loadPlugin loadplugfunc;
493   unloadPlugin unloadplugfunc;
494   bareosfuncs bareos_core_functions = {
495       sizeof(bareos_core_functions),
496       1,
497       registerBareosEvents,
498       getBareosValue,
499       setBareosValue,
500       JobMessage,
501       DebugMessage,
502       bareosMalloc,
503       bareosFree,
504   };
505   bareosinfos bareos_plugin_interface_version;
506 
507   pdata = allocpdata();
508   ParseArgs(pdata, argc, argv);
509 
510   bareos_plugin_interface_version.bfdinfo.size
511       = sizeof(bareos_plugin_interface_version);
512   bareos_plugin_interface_version.bfdinfo.version = DEFAULT_API_VERSION;
513 
514   pdata->pluginhandle = dlopen(pdata->pluginfile, RTLD_LAZY);
515   if (pdata->pluginhandle == NULL) {
516     printf("\nCannot load a plugin: %s\n\n", dlerror());
517     Freepdata(pdata);
518     exit(1);
519   }
520 
521   loadplugfunc = (loadPlugin)dlsym(pdata->pluginhandle, "loadPlugin");
522   if (loadplugfunc == NULL) {
523     printf("\nCannot find loadPlugin function: %s\n", dlerror());
524     printf("\nWhether the file is a really Bareos plugin?\n\n");
525     Freepdata(pdata);
526     exit(2);
527   }
528 
529   unloadplugfunc = (unloadPlugin)dlsym(pdata->pluginhandle, "unloadPlugin");
530   if (unloadplugfunc == NULL) {
531     printf("\nCannot find unloadPlugin function: %s\n", dlerror());
532     printf("\nWhether the file is a really Bareos plugin?\n\n");
533     Freepdata(pdata);
534     exit(3);
535   }
536 
537   if (pdata->bapiversion > 0) {
538     bareos_plugin_interface_version.bdirinfo.version = pdata->bapiversion;
539   }
540 
541   loadplugfunc(&bareos_plugin_interface_version, &bareos_core_functions,
542                (void**)&pdata->plugin_information,
543                (void**)&pdata->plugin_functions);
544 
545   pdata->bplugtype = Getplugintype(pdata);
546 
547   if (!pdata->listfunc) { DumpPluginfo(pdata); }
548   if ((!pdata->listinfo && pdata->listfunc) || pdata->verbose) {
549     DumpPlugfuncs(pdata);
550   }
551   printf("\n");
552 
553   unloadplugfunc();
554 
555   dlclose(pdata->pluginhandle);
556 
557   Freepdata(pdata);
558 
559   return 0;
560 }
561