device: renew dhcp leases on awake for software devices
[NetworkManager.git] / libnm-core / nm-vpn-editor-plugin.c
1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2 /*
3  * This library is free software; you can redistribute it and/or
4  * modify it under the terms of the GNU Lesser General Public
5  * License as published by the Free Software Foundation; either
6  * version 2 of the License, or (at your option) any later version.
7  *
8  * This library is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * Lesser General Public License for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public
14  * License along with this library; if not, write to the
15  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
16  * Boston, MA 02110-1301 USA.
17  *
18  * Copyright 2008 Novell, Inc.
19  * Copyright 2008 - 2010 Red Hat, Inc.
20  * Copyright 2015 Red Hat, Inc.
21  */
22
23 #include "nm-default.h"
24
25 #include "nm-vpn-editor-plugin.h"
26
27 #include "nm-core-internal.h"
28
29 static void nm_vpn_editor_plugin_default_init (NMVpnEditorPluginInterface *iface);
30
31 G_DEFINE_INTERFACE (NMVpnEditorPlugin, nm_vpn_editor_plugin, G_TYPE_OBJECT)
32
33 static void
34 nm_vpn_editor_plugin_default_init (NMVpnEditorPluginInterface *iface)
35 {
36         /* Properties */
37
38         /**
39          * NMVpnEditorPlugin:name:
40          *
41          * Short display name of the VPN plugin.
42          */
43         g_object_interface_install_property (iface,
44                  g_param_spec_string (NM_VPN_EDITOR_PLUGIN_NAME, "", "",
45                                       NULL,
46                                       G_PARAM_READABLE |
47                                       G_PARAM_STATIC_STRINGS));
48
49         /**
50          * NMVpnEditorPlugin:description:
51          *
52          * Longer description of the VPN plugin.
53          */
54         g_object_interface_install_property (iface,
55                  g_param_spec_string (NM_VPN_EDITOR_PLUGIN_DESCRIPTION, "", "",
56                                       NULL,
57                                       G_PARAM_READABLE |
58                                       G_PARAM_STATIC_STRINGS));
59
60         /**
61          * NMVpnEditorPlugin:service:
62          *
63          * D-Bus service name of the plugin's VPN service.
64          */
65         g_object_interface_install_property (iface,
66                  g_param_spec_string (NM_VPN_EDITOR_PLUGIN_SERVICE, "", "",
67                                       NULL,
68                                       G_PARAM_READABLE |
69                                       G_PARAM_STATIC_STRINGS));
70 }
71
72 /*********************************************************************/
73
74 /**
75  * nm_vpn_editor_plugin_load_from_file:
76  * @plugin_filename: The path to the share library to load.
77  *  Apply some common heuristics to find the library, such as
78  *  appending "so" file ending.
79  *  If the path is not an absolute path or no matching module
80  *  can be found, lookup inside a directory defined at compile time.
81  *  Due to this, @check_file might be called for two different paths.
82  * @check_service: if not-null, check that the loaded plugin advertises
83  *  the given service.
84  * @check_owner: if non-negative, check whether the file is owned
85  *  by UID @check_owner or by root. In this case also check that
86  *  the file is not writable by anybody else.
87  * @check_file: (scope call): optional callback to validate the file prior to
88  *   loading the shared library.
89  * @user_data: user data for @check_file
90  * @error: on failure the error reason.
91  *
92  * Load the shared libary @plugin_filename and create a new
93  * #NMVpnEditorPlugin instace via the #NMVpnEditorPluginFactory
94  * function.
95  *
96  * Returns: (transfer full): a new plugin instance or %NULL on error.
97  *
98  * Since: 1.2
99  */
100 NMVpnEditorPlugin *
101 nm_vpn_editor_plugin_load_from_file  (const char *plugin_filename,
102                                       const char *check_service,
103                                       int check_owner,
104                                       NMUtilsCheckFilePredicate check_file,
105                                       gpointer user_data,
106                                       GError **error)
107 {
108         GModule *module = NULL;
109         gs_free_error GError *local = NULL;
110         NMVpnEditorPluginFactory factory = NULL;
111         NMVpnEditorPlugin *editor_plugin = NULL;
112
113         g_return_val_if_fail (plugin_filename && *plugin_filename, NULL);
114
115         /* _nm_utils_check_module_file() fails with ENOENT if the plugin file
116          * does not exist. That is relevant, because nm-applet checks for that. */
117         if (_nm_utils_check_module_file (plugin_filename,
118                                              check_owner,
119                                              check_file,
120                                              user_data,
121                                              &local))
122                 module = g_module_open (plugin_filename, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
123
124         if (!module) {
125                 if (local) {
126                         g_propagate_error (error, local);
127                         local = NULL;
128                 } else {
129                         g_set_error (error,
130                                      NM_VPN_PLUGIN_ERROR,
131                                      NM_VPN_PLUGIN_ERROR_FAILED,
132                                      _("cannot load plugin %s"), plugin_filename);
133                 }
134                 return NULL;
135         }
136         g_clear_error (&local);
137
138         if (g_module_symbol (module, "nm_vpn_editor_plugin_factory", (gpointer) &factory)) {
139                 gs_free_error GError *factory_error = NULL;
140                 gboolean success = FALSE;
141
142                 editor_plugin = factory (&factory_error);
143
144                 g_assert (!editor_plugin || G_IS_OBJECT (editor_plugin));
145
146                 if (editor_plugin) {
147                         gs_free char *plug_name = NULL, *plug_service = NULL;
148
149                         /* Validate plugin properties */
150
151                         g_object_get (G_OBJECT (editor_plugin),
152                                       NM_VPN_EDITOR_PLUGIN_NAME, &plug_name,
153                                       NM_VPN_EDITOR_PLUGIN_SERVICE, &plug_service,
154                                       NULL);
155
156                         if (!plug_name || !*plug_name) {
157                                 g_set_error (error,
158                                              NM_VPN_PLUGIN_ERROR,
159                                              NM_VPN_PLUGIN_ERROR_FAILED,
160                                              _("cannot load VPN plugin in '%s': missing plugin name"),
161                                              g_module_name (module));
162                         } else if (   check_service
163                                    && g_strcmp0 (plug_service, check_service) != 0) {
164                                 g_set_error (error,
165                                              NM_VPN_PLUGIN_ERROR,
166                                              NM_VPN_PLUGIN_ERROR_FAILED,
167                                              _("cannot load VPN plugin in '%s': invalid service name"),
168                                              g_module_name (module));
169                         } else {
170                                 /* Success! */
171                                 g_object_set_data_full (G_OBJECT (editor_plugin), "gmodule", module,
172                                                         (GDestroyNotify) g_module_close);
173                                 success = TRUE;
174                         }
175                 } else {
176                         if (factory_error) {
177                                 g_propagate_error (error, factory_error);
178                                 factory_error = NULL;
179                         } else {
180                                 g_set_error (error,
181                                              NM_VPN_PLUGIN_ERROR,
182                                              NM_VPN_PLUGIN_ERROR_FAILED,
183                                              _("unknown error initializing plugin %s"), plugin_filename);
184                         }
185                 }
186
187                 if (!success) {
188                         g_module_close (module);
189                         editor_plugin = NULL;
190                 }
191         } else {
192                 g_set_error (error,
193                              NM_VPN_PLUGIN_ERROR,
194                              NM_VPN_PLUGIN_ERROR_FAILED,
195                              _("failed to load nm_vpn_editor_plugin_factory() from %s (%s)"),
196                              g_module_name (module), g_module_error ());
197                 g_module_close (module);
198                 editor_plugin = NULL;
199         }
200
201         return editor_plugin;
202 }
203
204 /*********************************************************************/
205
206 /**
207  * nm_vpn_editor_plugin_get_editor:
208  * @plugin: the #NMVpnEditorPlugin
209  * @connection: the #NMConnection to be edited
210  * @error: on return, an error or %NULL
211  *
212  * Returns: (transfer full): a new #NMVpnEditor or %NULL on error
213  */
214 NMVpnEditor *
215 nm_vpn_editor_plugin_get_editor (NMVpnEditorPlugin *plugin,
216                                  NMConnection *connection,
217                                  GError **error)
218 {
219         g_return_val_if_fail (NM_IS_VPN_EDITOR_PLUGIN (plugin), NULL);
220
221         return NM_VPN_EDITOR_PLUGIN_GET_INTERFACE (plugin)->get_editor (plugin, connection, error);
222 }
223
224 NMVpnEditorPluginCapability
225 nm_vpn_editor_plugin_get_capabilities (NMVpnEditorPlugin *plugin)
226 {
227         g_return_val_if_fail (NM_IS_VPN_EDITOR_PLUGIN (plugin), 0);
228
229         return NM_VPN_EDITOR_PLUGIN_GET_INTERFACE (plugin)->get_capabilities (plugin);
230 }
231
232 /**
233  * nm_vpn_editor_plugin_import:
234  * @plugin: the #NMVpnEditorPlugin
235  * @path: full path to the file to attempt to read into a new #NMConnection
236  * @error: on return, an error or %NULL
237  *
238  * Returns: (transfer full): a new #NMConnection imported from @path, or %NULL
239  * on error or if the file at @path was not recognized by this plugin
240  */
241 NMConnection *
242 nm_vpn_editor_plugin_import (NMVpnEditorPlugin *plugin,
243                              const char *path,
244                              GError **error)
245 {
246         g_return_val_if_fail (NM_IS_VPN_EDITOR_PLUGIN (plugin), NULL);
247
248         if (nm_vpn_editor_plugin_get_capabilities (plugin) & NM_VPN_EDITOR_PLUGIN_CAPABILITY_IMPORT) {
249                 g_return_val_if_fail (NM_VPN_EDITOR_PLUGIN_GET_INTERFACE (plugin)->import_from_file != NULL, NULL);
250                 return NM_VPN_EDITOR_PLUGIN_GET_INTERFACE (plugin)->import_from_file (plugin, path, error);
251         }
252
253         g_set_error (error,
254                      NM_VPN_PLUGIN_ERROR,
255                      NM_VPN_PLUGIN_ERROR_FAILED,
256                      _("the plugin does not support import capability"));
257         return NULL;
258 }
259
260 gboolean
261 nm_vpn_editor_plugin_export (NMVpnEditorPlugin *plugin,
262                              const char *path,
263                              NMConnection *connection,
264                              GError **error)
265 {
266         g_return_val_if_fail (NM_IS_VPN_EDITOR_PLUGIN (plugin), FALSE);
267
268         if (nm_vpn_editor_plugin_get_capabilities (plugin) & NM_VPN_EDITOR_PLUGIN_CAPABILITY_EXPORT) {
269                 g_return_val_if_fail (NM_VPN_EDITOR_PLUGIN_GET_INTERFACE (plugin)->export_to_file != NULL, FALSE);
270                 return NM_VPN_EDITOR_PLUGIN_GET_INTERFACE (plugin)->export_to_file (plugin, path, connection, error);
271         }
272
273         g_set_error (error,
274                      NM_VPN_PLUGIN_ERROR,
275                      NM_VPN_PLUGIN_ERROR_FAILED,
276                      _("the plugin does not support export capability"));
277         return FALSE;
278 }
279
280 char *
281 nm_vpn_editor_plugin_get_suggested_filename (NMVpnEditorPlugin *plugin,
282                                              NMConnection *connection)
283 {
284         g_return_val_if_fail (NM_IS_VPN_EDITOR_PLUGIN (plugin), NULL);
285
286         if (NM_VPN_EDITOR_PLUGIN_GET_INTERFACE (plugin)->get_suggested_filename)
287                 return NM_VPN_EDITOR_PLUGIN_GET_INTERFACE (plugin)->get_suggested_filename (plugin, connection);
288         return NULL;
289 }
290