$Id: plugins.txt,v 1.8 2003/05/11 17:21:57 aquamaniac Exp $ This file describes how to add a Medium-Plugin to OpenHBCI. What Is A Medium Plugin ? ========================= A medium is something used to store the user's cryptographic keys. They can be stored in a key file with some file format, or on a chipcard, or on whatever type of medium you want to implement. A medium plugin is a mechanism which provides support for a medium. E.g., the plugin "DDVCard" provides support for DDV chipcards, so with this plugin installed you are able to use such a card. A plugin is either loaded on demand at run-time or statically linked into OpenHBCI. Rules For Creating a Medium Plugin ================================== A plugin must follow these rules in order to be useable with OpenHBCI. Medium Type String ------------------ A plugin for a specifc medium is identified by a unique medium type string, e.g. "DDVCard", "RSACard", or "RDHFile". This string is the identification by which an application may query whether this plugin can be loaded. Filename -------- When OpenHBCI is asked to create a medium of the type "DDVCard" it performs these actions: - check whether a plugin is already loaded which provides this type - if it is not: - take the name of the medium type (in this case "DDVCard") - change it to lower cases (->"ddvcard") - append the extension used on the running system (on Linux: ".so") (-> "ddvcard.so") - look for a file of that name in the system wide OpenHBCI plugin folder. You can get this folder with the command "openhbci-config --plugins" So the name of the file must be the lower cased medium type string plus the shared object file extension used on the current operating system. Exported Symbols ---------------- The following symbols (see nm(1)) must be defined in any new plugin: int @PLUGINNAME@_openhbci_plugin_interface_version; /* This is the plugin interface version of OpenHBCI, which is necessary so that old plugins can be handled as well. For new plugins, it has to be set to the current value of OPENHBCI_PLUGIN_INTERFACE_VERSION */ int @PLUGINNAME@_openhbci_module_current; int @PLUGINNAME@_openhbci_module_revision; int @PLUGINNAME@_openhbci_module_age; /* The above three numbers are the version number of the given plugin implementation. The three version numbers are handled in the same way as libtool's versioning system. See the info pages of libtool. */ HBCI::Error @PLUGINNAME@_registerYourSelf(HBCI::API *api); /* This is the initialization function for the plugin. See below. */ If any of these symbols cannot be found, the plugin loader interface will return an error message and refuse to load the plugin. Please note that @PLUGINNAME@ stands for the name of your plugin (no capitals). Each exported symbol must have this prefix to avoid namespace collisions when linking a plugin statically to OpenHBCI. RegisterYourSelf ---------------- This is the function OpenHBCI uses to initialize the plugin. It may perform whatever actions it needs to perform. However, the first thing this function should do is to check the version of OpenHBCI used and compare it against that version which was used when the plugin has been compiled. RULE 1: A plugin should refuse to work if the currently running version of OpenHBCI is older than that one used to compile the plugin! In that case, the plugin's function registerYourSelf() should return an HBCI::Error with error code [FIXME: Give error code here]. [FIXME: Isn't this a bit too strict? Shouldn't it be allowed if only the patchlevel and/or minor changed?] RULE 2: If the major version number of the running OpenHBCI library differs from the one used to compile the plugin, then the plugin should refuse to work, too, and return a HBCI::Error with erro code [FIXME: give error code here.] If the version check succeeds, then this function should instantiate an object of a class that inherits HBCI::MediumPlugin (in our example this is HBCI::DDVCardPlugin) and call api->registerMediumPlugin() with this object, thus registering the new plugin. Important Classes ================= When writing your own MediumPlugin you will find the following classes helpful: - HBCI::Medium -- Abstract base class for any security medium - HBCI::Plugin -- Abstract base class for any plugin - HBCI::MediumPlugin -- Abstract base class for medium plugin A nice example of how to create a plugin is the RDHFile plugin located in "src/plugins/keyfile". Note: The class PluginFile is not intended to be inherited by a plugin, despite its name. Instead, that class is used internally by OpenHBCI's plugin loader interface to manage the known plugins. You probably do not need to inherit that class. Caveats ======= Most likely your new medium plugin is written in C++. However, to be able to lookup the exported symbols through dlsym(3), the exported symbols must be declared with the 'extern "C"' binding prefix. Otherwise, due to each C++ compiler's name mangling, it would not be possible to lookup the symbols by dlsym(). So you need to use the binding prefix `extern "C"`. The following example will work: -------------------------------------------------X8 extern "C" { int @PLUGINNAME@_openhbci_plugin_interface_version = OPENHBCI_PLUGIN_INTERFACE_VERSION; int @PLUGINNAME@_openhbci_module_current=DDVCARD_MODULE_CURRENT; int @PLUGINNAME@_openhbci_module_revision=DDVCARD_MODULE_REVISION; int @PLUGINNAME@_openhbci_module_age=DDVCARD_MODULE_AGE; HBCI::Error @PLUGINNAME@_registerYourSelf(HBCI::API *api) { // do initialization here } }; // extern "C" -------------------------------------------------X8 Please note that ONLY these symbols (functions, variables) MUST be declared within the 'extern "C"' statement. All other symbols MUST NOT! More Usefull Rules ================== Unfortunately old GCC compilers (before 3.0) have very big problems with code that loads C++-libraries via dlopen(3). These problems make the new plugin system of OpenHBCI useles on those systems. However, in such a case OpenHBCI is able to statically link against your plugin, if you respect the following additional rules: RULE 1: Your makefiles must include rules that additionally allow building of a conveniance library. Normally your Makefile.am looks like this: -------------------------------------------------X8 plugindir=@PLUGIN_PATH@/media plugin_LTLIBRARIES=ddvcard.la ddvcard_la_SOURCES=ddvcard.cpp mediumddv.cpp ddvcard_la_LDFLAGS=-module -version-info 0:0:0 ddvcard_la_LIBADD=@libchipcard_libs@ -------------------------------------------------X8 This builds the plugin module. Now you should add the following to your Makefile.am: -------------------------------------------------X8 noinst_LTLIBRARIES=libddvcard.la libddvcard_la_SOURCES=ddvcard.cpp mediumddv.cpp libddvcard_la_LIBADD=@libchipcard_libs@ -------------------------------------------------X8 As you can see these rules are the same as those for building the module, except that the options "-module" and "-version-info" are missing. These rules create a standard library against which OpenHBCI can be linked. RULE 2: The main folder of your package should contain a file named "LIBRARY". This should contain the relative path and name of the library for statical linking (e.g. "src/libddvcard.la"). If this file is missing then the name of the folder containing the plugin plus ".la" is used. RULE 3: The main folder of your package should contain a file named "PLUGINNAME" which holds the name of the plugin in lower cased (e.g. "ddvcard"). If this file is missing then the name of the folder containing the plugin is used. Examples ======== Please have a look at the plugin "openhbci-ddvcard". You can get it - via CVS: "cvs -d:anonymous@cvs.openhbci.sf.net:/cvsroot/openhbci login" <Leave Password empty> "cvs -d:anonymous@cvs.openhbci.sf.net:/cvsroot/openhbci co plugins" <THIS DOWNLOADS THE PLUGINS> - later from the OpenHBCI site (http://www.openhbci.de)