This makes package updates more robust, avoiding in-place replaces of
the plugins.
Previously, if an upgrade transaction was terminated, NetworkManager
library could end up being of a different version than the plugins.
If the user was unfortunate enough to connect using a connection that
required a plugin (say, Wi-Fi), he would be left without a network
connection making it somewhat inconvenient to recover from the botched
upgrade.
This makes the whole situation a little bit less sad.
The VPN plugins are kept where they always have been -- the path is not
qualified with a version number.
Let VPN plugins return a virtual function table to extend
the API while bypassing libnm. This allows to add and use
new functionality to VPN plugins without updating libnm.
The actual definitions are in a header-only file
"nm-vpn-editor-plugin-call.h", which can be copied to the
caller/plugin.
The NMVpnPluginInfo is essentially the .name file, that is, a
configuration file about the plugin itself. Via NMVpnPluginInfo
instance, the NMVpnEditorPlugin can be created.
Usually, one would create a NMVpnPluginInfo (that is, reading the
.name file) and then create a NMVpnEditorPlugin instance from there.
In this case, usually the editor-plugin is owned by the plugin-info
instance (although the API allows for creating the editor-plugin
independently).
Now, pass the NMVpnPluginInfo to the editor-plugin too.
This is useful, because then the editor-plugin can look at the .name
file.
The .name file is not user configuration. Instead it is configuration
about the plugin itself. Although the .name file is part of the plugin
build artefacts, it is useful to allow the plugin to access the .name
file. The reason is, that this can allow the user to easily change a
configuration knob of the plugin without requiring to patch or the
plugin.
<gmodule.h> is implicitly included by <gio/gio.h> which is available
everywhere. For that reason, we would not have to include this header
at all. However, it is recommended to explicitly include <gmodule.h>
where needed.
So, include it where needed -- if <gio/gio.h> wouldn't be there --
and drop it from where it is not needed.
Closing the library will interfere badly as the glib types cannot be
unregistered. We must leak the library handle.
Switch to dlopen() instead of g_module_open(), because the former
supports RTLD_NOLOAD. This is useful for two reasons:
- checking the file prior loading only makes any sense when
dlopen() would actually load a file anew.
- if the library was loaded before, we want to return the handle.
On the other hand, if the library was not loaded, we leak the
handle.
Thereby, refactor the code from if-else blocks to return-early, because
the function nicely does individual steps and if one fails just error
out.
In commit ca000cffbb, we changed to
accept a plugin library name without path. One reason for that
is to keep architecture dependent parts out of the .name file
and possibly support multilib.
However, the shared libraries of VPN plugins are not installed in
a global library search path, but for example into
"/usr/lib64/NetworkManager/libnm-vpn-plugin-openvpn.so".
In that case, specifying "plugin=libnm-vpn-plugin-openvpn.so"
would not be enough to find plugin.
Instead, when configuring a plugin name without path, assume
it is in NMPLUGINDIR directory. Modify nm_vpn_editor_plugin_load_from_file()
to allow path-less plugin-names. Previously such names would be rejected
as not being absolute. This API allows to do file verification
before loading the plugin, but it now supports prepending NMPLUGINDIR
to the plugin name. Basically, this function mangles the plugin_name
argument and checks that such a file exists.
The recently added nm_vpn_editor_plugin_load() continues to behave
as before: it does no checks whatsoever and passes the name directly
to dlopen(). That way, it uses system search paths like LD_LIBRARY_PATH
and performs no checks on the file.
Fixes: ca000cffbb
Contrary to nm_vpn_editor_plugin_load_from_file(), this allows
to specify a library name without path. In this case, g_module_open()
(dlopen()) will search for a library in various system directories.
Since commit 3dfbbb227e, we enforce that
the plugin path in the .name file is absolute and we perform several
checks on the file before loading it (ownership, etc).
Relax that, to also allow libray names without path component.
In that case, g_module_open()/dlopen() will search for a library
in various search paths. This allows, to omit absolute paths
in the .name file. The latter is problematic, because by default
we install the .name file in the architecture independent location
/usr/lib/NetworkManager. As such, it should not contain paths
to architecture dependent libraries. With this change, a .name
file can contain only the library name and it will be loaded
using the usual mechanism.
However, specifying absolute paths is still possible and works
same as before, including checking file permissions.
As such, distributions probably should package the VPN plugins
to have no path in the .name file. On the other hand, a user
compiling from source probably wants to specify an absolute
path. The reason is, that the user probably doesn't build the
plugin for multiple achitectures and that way, he can install
the plugin in a separate (private) prefix.
- All internal source files (except "examples", which are not internal)
should include "config.h" first. As also all internal source
files should include "nm-default.h", let "config.h" be included
by "nm-default.h" and include "nm-default.h" as first in every
source file.
We already wanted to include "nm-default.h" before other headers
because it might contains some fixes (like "nm-glib.h" compatibility)
that is required first.
- After including "nm-default.h", we optinally allow for including the
corresponding header file for the source file at hand. The idea
is to ensure that each header file is self contained.
- Don't include "config.h" or "nm-default.h" in any header file
(except "nm-sd-adapt.h"). Public headers anyway must not include
these headers, and internal headers are never included after
"nm-default.h", as of the first previous point.
- Include all internal headers with quotes instead of angle brackets.
In practice it doesn't matter, because in our public headers we must
include other headers with angle brackets. As we use our public
headers also to compile our interal source files, effectively the
result must be the same. Still do it for consistency.
- Except for <config.h> itself. Include it with angle brackets as suggested by
https://www.gnu.org/software/autoconf/manual/autoconf.html#Configuration-Headers
- "gsystem-local-alloc.h" and <gio/gio.h> are already included via
"nm-default.h". No need to include them separately.
- include "nm-macros-internal.h" via "nm-default.h" and drop all
explict includes.
- in the modified files, ensure that we always include "config.h"
and "nm-default.h" first. As second, include the header file
for the current source file (if applicable). Then follow external
includes and finally internal nm includes.
- include nm headers inside source code files with quotes
- internal header files don't need to include default headers.
They can savely assume that "nm-default.h" is already included
and with it glib, nm-glib.h, nm-macros-internal.h, etc.
VPN plugins are usually split into different packages. It might
be that the plugin file is simply not installed. We want the caller
to be able to recognize that conditation to fail gracefully.
Thus return a certain error code.
Originally, nm-applet loaded the vpn plugins by passing the filename
to g_module_open(). Thereby, g_module_open() allowed for missing file
extension and tries to complete the name with a system-dependent suffix.
When porting to libnm, we kept that behavior but did more elaborate
checks on the file, like checking owner and permissions.
Change to no longer trying to append the system suffix, but require
an exact path. That is no usability problem, because the plugin path
is specified in the .name files, and we just require them now to be the
full path (including the .so extension).
Note also, that this only affects new, libnm-based vpn plugins, thus there
is no change in behavior for legacy libnm-glib based plugins.
Fixes: eed0d0c58f
The localization headers are now included via "nm-default.h".
Also fixes several places, where we wrongly included <glib/gi18n-lib.h>
instead of <glib/gi18n.h>. For example under "clients/" directory.
Split the content of libnm/nm-vpn-editor-plugin.h and
move NMVpnEditorPlugin to libnm-core/nm-vpn-editor-plugin.h.
VPN plugins allow us to extend functionality about VPNs.
This can be also useful for NetworkManager core, hence
move that part to libnm-core.
The name NMVpnEditorPlugin is slightly misleading but not completely
wrong. The "editor" part stands no longer for bringing nm-applet
functionality (alone), but enable general VPN functionality in
the client.
Especially because we already have NMVpnPluginOld with a different
meaning (i.e. a base class of the plugin server implementation).