Add DBUS communication in dbus.py, update README and add changes to sources

master
Max Moser 2017-12-20 13:00:13 +01:00
parent d606210675
commit fb4cfa2413
4 changed files with 170 additions and 18 deletions

View File

@ -14,4 +14,20 @@
The following section briefly describes how to start the stuff for testing purposes The following section briefly describes how to start the stuff for testing purposes
* `./src/nm-openvpn-service --bus-name org.freedesktop.NetworkManager.wireguard` to start the plugin * `./src/nm-openvpn-service --bus-name org.freedesktop.NetworkManager.wireguard` to start the plugin
* `examples/dbus/dbus.py` to send Disconnect() to the plugin * `examples/dbus/dbus.py` to send Disconnect() to the plugin
## Files
The following is a list of files that I created over the course of the project and is mainly for myself to keep track of them.
* `nm-wireguard-service.conf`
* `includes2strings.py`
## Knowledge
* The wireguard plugin basically handles incoming DBUS requests for the *NM VPN Plugin Interface* (can be looked at via `examples/dbus/dbus.py`)
* `auth-dialog/nm-openvpn-auth-dialog` reads the secrets from STDIN until the string "DONE" occurs and then proceeds to handle them
NM VPN Plugin:
https://developer.gnome.org/libnm-glib/stable/libnm-glib-NMVPNPlugin.html
Settings VPN (sent via DBus on Connect(a{sa{sv}}) method):
https://developer.gnome.org/libnm/stable/NMSettingVpn.html#nm-setting-vpn-get-data-item

View File

@ -457,6 +457,8 @@ main (int argc, char *argv[])
AskUserFunc ask_user_func = NULL; AskUserFunc ask_user_func = NULL;
FinishFunc finish_func = NULL; FinishFunc finish_func = NULL;
// this describes how the arguments are supposed to be parsed
// e.g. "-u UUID"
GOptionContext *context; GOptionContext *context;
GOptionEntry entries[] = { GOptionEntry entries[] = {
{ "reprompt", 'r', 0, G_OPTION_ARG_NONE, &retry, "Reprompt for passwords", NULL}, { "reprompt", 'r', 0, G_OPTION_ARG_NONE, &retry, "Reprompt for passwords", NULL},
@ -485,16 +487,22 @@ main (int argc, char *argv[])
return EXIT_FAILURE; return EXIT_FAILURE;
} }
// the parameters are supplied via arguments
printf("UUID: %s, Name: %s, Service: %s\n", vpn_uuid, vpn_name, vpn_service);
if (strcmp (vpn_service, NM_VPN_SERVICE_TYPE_OPENVPN) != 0) { if (strcmp (vpn_service, NM_VPN_SERVICE_TYPE_OPENVPN) != 0) {
fprintf (stderr, "This dialog only works with the '%s' service\n", NM_VPN_SERVICE_TYPE_OPENVPN); fprintf (stderr, "This dialog only works with the '%s' service\n", NM_VPN_SERVICE_TYPE_OPENVPN);
return EXIT_FAILURE; return EXIT_FAILURE;
} }
printf("Reading stdin details\n");
// reads secrets/data from STDIN until "DONE" is read
if (!nm_vpn_service_plugin_read_vpn_details (0, &data, &secrets)) { if (!nm_vpn_service_plugin_read_vpn_details (0, &data, &secrets)) {
fprintf (stderr, "Failed to read '%s' (%s) data and secrets from stdin.\n", fprintf (stderr, "Failed to read '%s' (%s) data and secrets from stdin.\n",
vpn_name, vpn_uuid); vpn_name, vpn_uuid);
return 1; //return 1; // TODO re-add
} }
printf("Done reading\n");
if (external_ui_mode) { if (external_ui_mode) {
no_secrets_required_func = eui_no_secrets_required; no_secrets_required_func = eui_no_secrets_required;

View File

@ -24,12 +24,14 @@ show_introspect = True
def send_desktop_notification(title="Hello World", msg="pydbus works!"): def send_desktop_notification(title="Hello World", msg="pydbus works!"):
"""Send a notification to the desktop environment to display""" """Send a notification to the desktop environment to display"""
bus = SessionBus() bus = SessionBus()
notifications = bus.get('.Notifications') notifications = bus.get('.Notifications')
notifications.Notify('test', 0, 'dialog-information', title, msg, [], {}, 5000) notifications.Notify('test', 0, 'dialog-information', title, msg, [], {}, 5000)
def list_systemd_units(): def list_systemd_units():
"""Fetch all systemd units and print them""" """Fetch all systemd units and print them"""
bus = SystemBus() bus = SystemBus()
# systemd is now a proxy for the .systemd1 remote object # systemd is now a proxy for the .systemd1 remote object
@ -42,6 +44,7 @@ def list_systemd_units():
def stop_start_systemd_unit(name="ssh.service"): def stop_start_systemd_unit(name="ssh.service"):
"""Stop and restart a systemd unit""" """Stop and restart a systemd unit"""
bus = SystemBus() bus = SystemBus()
# systemd is now a proxy for the .systemd1 remote object # systemd is now a proxy for the .systemd1 remote object
@ -51,6 +54,7 @@ def stop_start_systemd_unit(name="ssh.service"):
def watch_for_new_systemd_jobs(): def watch_for_new_systemd_jobs():
"""Wait for new systemd units and when they are created, print them out""" """Wait for new systemd units and when they are created, print them out"""
bus = SystemBus() bus = SystemBus()
# systemd is now a proxy for the .systemd1 remote object # systemd is now a proxy for the .systemd1 remote object
@ -76,8 +80,9 @@ def hibernate():
else: else:
print("Cannot hibernate") print("Cannot hibernate")
except GLib.Error as e: except Exception as ex:
print("Could not get PowerManager from DBUS") print("Could not get PowerManager from DBUS")
print(str(ex))
def get_wg_plugin(bus_name="org.freedesktop.NetworkManager.wireguard", def get_wg_plugin(bus_name="org.freedesktop.NetworkManager.wireguard",
@ -98,15 +103,39 @@ def get_wg_plugin(bus_name="org.freedesktop.NetworkManager.wireguard",
def wg_disconnect(wg_plugin): def wg_disconnect(wg_plugin):
"""Disconnect the WG VPN plugin""" """Disconnect the WG VPN plugin"""
wg_plugin.Disconnect() wg_plugin.Disconnect()
def wg_connect(wg_plugin):
"""Send the Connect Command to the Wireguard Plugin"""
# these are the settings that are expected by Connect(a{sa{sv}}) for a VPN plugin
service_type = GLib.Variant("s", "service")
user_name = GLib.Variant("s", "wireguard")
persistent = GLib.Variant("b", False)
data = GLib.Variant("a{ss}", {"maxi": "cool"})
secrets = GLib.Variant("a{ss}", {"name": "maxi moser"})
timeout = GLib.Variant("u", 1337)
# The DBus type: a{sa{sv}}
# is a Dictionary with...
# Key: Type ("wireless", "wired", "vpn", ...) -- we want VPN
# Value: Dictionary with Key: Setting Name, Value: Setting Value
settings = {"vpn":
{"service-type": service_type,
"user-name": user_name,
"persistent": persistent,
"data": data,
"secrets": secrets,
"timeout": timeout}
}
wg_plugin.Connect(settings)
show_introspect = False show_introspect = False
if __name__ == "__main__": if __name__ == "__main__":
# send_desktop_notification("Guten Tag", "pydbus funktioniert, mein Herr!") # send_desktop_notification("Guten Tag", "pydbus funktioniert, mein Herr!")
# list_systemd_units()
# hibernate()
try: try:
wg = get_wg_plugin() wg = get_wg_plugin()
@ -114,7 +143,7 @@ if __name__ == "__main__":
print(wg.Introspect()) print(wg.Introspect())
help(wg) help(wg)
wg_disconnect(wg) wg_connect(wg)
except Exception as ex: except Exception as ex:
print(str(ex)) print(str(ex))

View File

@ -236,6 +236,28 @@ _LOGD_enabled (void)
/*****************************************************************************/ /*****************************************************************************/
static const char *
wg_quick_find_exepath (void)
{
static const char *paths[] = {
"/usr/sbin/wg-quick",
"/usr/bin/wg-quick",
"/sbin/wg-quick",
"/bin/wg-quick",
"/usr/local/sbin/wg-quick",
"/usr/local/bin/wg-quick",
};
int i;
for (i = 0; i < G_N_ELEMENTS(paths); i++) {
if (g_file_test (paths[i], G_FILE_TEST_EXISTS)) {
return paths[i];
}
}
return NULL;
}
static const char * static const char *
openvpn_binary_find_exepath (void) openvpn_binary_find_exepath (void)
{ {
@ -393,6 +415,59 @@ pids_pending_add (GPid pid, NMWireguardPlugin *plugin)
gl.pids_pending_list = g_slist_prepend (gl.pids_pending_list, pid_data); gl.pids_pending_list = g_slist_prepend (gl.pids_pending_list, pid_data);
} }
// TODO implement me right
wg_quick_closed(GPid pid, gint status, gpointer user_data){
PidsPendingData *pid_data = user_data;
NMWireguardPlugin *plugin;
if (WIFEXITED (status)) {
int exit_status;
exit_status = WEXITSTATUS (status);
if (exit_status != 0)
_LOGW ("wg-quick[%ld] exited with error code %d", (long) pid, exit_status);
else
_LOGI ("wg-quick[%ld] exited with success", (long) pid);
}
else if (WIFSTOPPED (status))
_LOGW ("wg-quick[%ld] stopped unexpectedly with signal %d", (long) pid, WSTOPSIG (status));
else if (WIFSIGNALED (status))
_LOGW ("wg-quick[%ld] died with signal %d", (long) pid, WTERMSIG (status));
else
_LOGW ("wg-quick[%ld] died from an unnatural cause", (long) pid);
g_return_if_fail (pid_data);
g_return_if_fail (pid_data->pid == pid);
g_return_if_fail (g_slist_find (gl.pids_pending_list, pid_data));
plugin = pid_data->plugin;
pid_data->watch_id = 0;
gl.pids_pending_list = g_slist_remove (gl.pids_pending_list , pid_data);
pids_pending_data_free (pid_data);
}
// TODO implement me right
static void
pids_pending_add_wg (GPid pid, NMWireguardPlugin *plugin)
{
PidsPendingData *pid_data;
g_return_if_fail (NM_IS_WIREGUARD_PLUGIN (plugin));
g_return_if_fail (pid > 0);
_LOGI ("wg-quick[%ld] started", (long) pid);
pid_data = g_slice_new (PidsPendingData);
pid_data->pid = pid;
pid_data->kill_id = 0;
pid_data->watch_id = g_child_watch_add (pid, wg_quick_closed, pid_data);
pid_data->plugin = plugin;
g_object_add_weak_pointer ((GObject *) plugin, (gpointer *) &pid_data->plugin);
gl.pids_pending_list = g_slist_prepend (gl.pids_pending_list, pid_data);
}
static gboolean static gboolean
pids_pending_ensure_killed (gpointer user_data) pids_pending_ensure_killed (gpointer user_data)
{ {
@ -2038,23 +2113,47 @@ real_disconnect (NMVpnServicePlugin *plugin,
static gboolean static gboolean
test_connect (NMVpnServicePlugin *plugin, test_connect (NMVpnServicePlugin *plugin,
NMConnection *connection, NMConnection *connection,
GError **error) GError **err)
{ {
_LOGI("Did a dummy connect");
/* NMSettingVpn *setting = nm_connection_get_setting_vpn(connection);
printf("I Know It!\n"); char *secret = nm_setting_vpn_get_secret(setting, "name");
// FIXME find something useful char *str_setting = nm_setting_to_string(setting);
char **cmd = {"touch", "/home/maxmanski/iknowhwatyoudidlastsummer", NULL}; char *wg_quick_path = wg_quick_find_exepath();
GPid pid = 0; //char *
GSpawnFlags spawn_flags = G_SPAWN_DO_NOT_REAP_CHILD;
spawn_flags = G_SPAWN_DEFAULT;
if (!g_spawn_async (NULL, cmd, NULL, spawn_flags, NULL, NULL, &pid, error)){ if(wg_quick_path == NULL){
_LOGW("Error: Could not find wg-quick!");
return FALSE; return FALSE;
} }
*/
printf("Setting to String: %s\n", str_setting);
printf("Secret: %s\n", secret);
//char **cmd = {wg_quick_path, "up", "mullvad", NULL};
char **cmd = {"/usr/bin/touch", "/home/maxmanski/uwotm8", NULL};
GPid pid = 0;
GSpawnFlags spawn_flags = G_SPAWN_DO_NOT_REAP_CHILD;
spawn_flags = G_SPAWN_STDERR_TO_DEV_NULL | G_SPAWN_STDOUT_TO_DEV_NULL;
spawn_flags = G_SPAWN_DEFAULT | G_SPAWN_DO_NOT_REAP_CHILD;
// if (!g_spawn_async (NULL, cmd, NULL, spawn_flags, NULL, NULL, &pid, err)){
int exit_code = 0;
*err = NULL; // TODO remove?
if (!g_spawn_async(NULL, cmd, NULL, spawn_flags, NULL, NULL, &pid, err)){
_LOGW("An error occured while spawning wg-quick! (Error: %s)", (*err)->message);
return FALSE;
}
pids_pending_add_wg(pid, plugin);
printf("PID of spawned command: %d\n", pid);
// note: exit code 139 means SIGSEV (program died because of segfault or so)
{
printf("WG set up and ready to go!\n");
}
_LOGI("Did a dummy connect");
return TRUE; return TRUE;
} }