--- /dev/null
+/*
+ * This file is part of vpngui
+ *
+ * Copyright © 2009 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * */
+
+#include <glib.h>
+#include <stdlib.h>
+#include <sys/wait.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "vpngui.h"
+
+/* these are pretty much copy-pasted from networkmanager-vpnc... */
+
+static void vpnc_watch_cb(GPid pid, gint status, gpointer data)
+{
+ PluginInfo *info;
+ g_return_if_fail(data);
+ info = (PluginInfo *)data;
+ guint error = -1;
+ gchar *errmsg = NULL;
+ PluginInfoPrivate *priv = VPNGUI_PLUGIN_GET_PRIVATE (info);
+ gboolean forced_disconnection = (VPN_FORCED_DISCONNECTING == priv->state);
+
+ g_debug("Executing %s", __PRETTY_FUNCTION__);
+
+ switch(priv->state) {
+ case VPN_CONNECTING:
+ /* if we get here during connecting things went foobar... */
+ set_state(info, VPN_CONNECT_FAILED);
+ break;
+ case VPN_DISCONNECTING:
+ case VPN_FORCED_DISCONNECTING:
+ set_state(info, VPN_DISCONNECTED);
+ break;
+ case VPN_DISCONNECTED:
+ break;
+ default:
+ set_state(info, VPN_DISCONNECTED);
+ };
+ if(!forced_disconnection) {
+ if (WIFEXITED(status)) {
+ error = WEXITSTATUS(status);
+ if (error != 0) {
+
+ // Nasty hack: vpnc 0.5.1 returns with code 256 on erroneous auth.
+ // but maybe it returns with 256 on other cases to.
+ /// @todo Check vpnc errorcodes.
+ if ( status == 256 ) errmsg = NULL;//g_strdup_printf("Authentication failed");
+ else
+ errmsg = g_strdup_printf("Vpnc exited with error code %d\n", status);
+
+ }
+ } else if (WIFSTOPPED(status)) {
+ errmsg = g_strdup_printf("Vpnc was stopped unexpectedly");
+ } else if (WIFSIGNALED(status)) {
+ errmsg = g_strdup_printf("Vpnc died from signal %d", WTERMSIG (status));
+ } else {
+ errmsg = g_strdup_printf("Vpnc died under suspicious circumstances");
+ }
+ };
+ g_spawn_close_pid(priv->vpnc_pid);
+
+ priv->vpnc_pid = 0;
+
+ switch (error) {
+ case 2:
+ error_msg("Authentication failed");
+ break;
+ case 1:
+ if (errmsg)
+ error_msg("Error:\n%s", errmsg);
+ break;
+ default:
+ break;
+ }
+ if (errmsg) {
+ g_free(errmsg);
+ }
+
+ g_debug("Exiting %s", __PRETTY_FUNCTION__);
+}
+
+gboolean vpnc_start(PluginInfo *info)
+{
+ GPid pid;
+ GPtrArray *vpnc_argv;
+ GError *error = NULL;
+ GSource *vpnc_watch;
+ gint stdin_fd = -1;
+ g_debug("Executing %s", __PRETTY_FUNCTION__);
+
+ g_return_val_if_fail (info != NULL, FALSE);
+
+ PluginInfoPrivate *priv = VPNGUI_PLUGIN_GET_PRIVATE (info);
+
+ priv->vpnc_pid = 0;
+
+ vpnc_argv = g_ptr_array_new();
+ g_ptr_array_add (vpnc_argv, (gpointer) "/usr/bin/sudo");
+ g_ptr_array_add (vpnc_argv, (gpointer) "/usr/sbin/vpngui-helper");
+ g_ptr_array_add (vpnc_argv, (gpointer) "connect");
+ g_ptr_array_add (vpnc_argv, (gpointer) "--non-inter");
+ g_ptr_array_add (vpnc_argv, (gpointer) "--no-detach");
+ g_ptr_array_add (vpnc_argv, (gpointer) priv->vpnc_config);
+ g_ptr_array_add (vpnc_argv, NULL);
+
+ if (!g_spawn_async_with_pipes (NULL, (char **) vpnc_argv->pdata, NULL,
+ G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &pid, &stdin_fd,
+ NULL, NULL, &error)) {
+ g_ptr_array_free (vpnc_argv, TRUE);
+ error_msg("vpnc failed to start: %s\n", error->message);
+ g_error_free(error);
+ return FALSE;
+ }
+
+ g_ptr_array_free (vpnc_argv, TRUE);
+
+ g_debug("%s: vpnc started with pid %d", __PRETTY_FUNCTION__, pid);
+ set_state(info, VPN_CONNECTING);
+
+ vpnc_watch = g_child_watch_source_new (pid);
+ g_source_set_callback (vpnc_watch, (GSourceFunc) vpnc_watch_cb, info, NULL);
+
+ g_source_attach (vpnc_watch, NULL);
+
+ priv->vpnc_pid = pid;
+ priv->vpnc_watch_id = g_source_get_id(vpnc_watch);
+
+ g_source_unref (vpnc_watch);
+ g_debug("Exiting %s", __PRETTY_FUNCTION__);
+ return TRUE;
+}
+
+/*
+ * start the vpnc killer - we'll get notified of vpnc actually
+ * dying elsewhere so we don't care about the results here
+ */
+gboolean vpnc_stop(PluginInfo *info, const gboolean forced)
+{
+ GPtrArray *vpnc_argv;
+ GError *error = NULL;
+ gchar *pid;
+
+ g_debug("Executing %s, forced = %d", __PRETTY_FUNCTION__, forced);
+
+ g_return_val_if_fail (info != NULL, FALSE);
+ PluginInfoPrivate *priv = VPNGUI_PLUGIN_GET_PRIVATE (info);
+
+ if (priv->vpnc_pid == 0) {
+ return TRUE;
+ }
+
+ pid = g_strdup_printf("%d", priv->vpnc_pid);
+
+ vpnc_argv = g_ptr_array_new();
+ g_ptr_array_add (vpnc_argv, (gpointer) "/usr/bin/sudo");
+ g_ptr_array_add (vpnc_argv, (gpointer) "/usr/sbin/vpngui-helper");
+ g_ptr_array_add (vpnc_argv, (gpointer) "disconnect");
+ g_ptr_array_add (vpnc_argv, (gpointer) pid);
+ g_ptr_array_add (vpnc_argv, NULL);
+
+ if (!g_spawn_async(NULL, (char **) vpnc_argv->pdata, NULL,
+ 0, NULL, NULL, NULL, &error)) {
+ g_ptr_array_free (vpnc_argv, TRUE);
+ error_msg("vpn disconnect failed to start: %s\n", error->message);
+ g_error_free(error);
+ g_free(pid);
+ return FALSE;
+ }
+ set_state(info, forced ? VPN_FORCED_DISCONNECTING : VPN_DISCONNECTING);
+
+ /* unregister the vpnc watcher, we'll get notified by dbus on disconnect */
+// g_source_remove(info->vpnc_watch_id);
+// info->vpnc_watch_id = 0;
+
+ g_ptr_array_free (vpnc_argv, TRUE);
+ g_free(pid);
+
+ return TRUE;
+}
+
+gboolean vpnc_restart(PluginInfo *info)
+{
+ GPtrArray *vpnc_argv;
+ GError *error = NULL;
+ gchar *pid;
+
+ g_debug("Executing %s", __PRETTY_FUNCTION__);
+
+ g_return_val_if_fail (info != NULL, FALSE);
+ PluginInfoPrivate *priv = VPNGUI_PLUGIN_GET_PRIVATE (info);
+
+ if (priv->vpnc_pid == 0) {
+ return TRUE;
+ }
+
+ pid = g_strdup_printf("%d", priv->vpnc_pid);
+
+ vpnc_argv = g_ptr_array_new();
+ g_ptr_array_add (vpnc_argv, (gpointer) "/usr/bin/sudo");
+ g_ptr_array_add (vpnc_argv, (gpointer) "/usr/sbin/vpngui-helper");
+ g_ptr_array_add (vpnc_argv, (gpointer) "reconnect");
+ g_ptr_array_add (vpnc_argv, (gpointer) pid);
+ g_ptr_array_add (vpnc_argv, NULL);
+
+ if (!g_spawn_async(NULL, (char **) vpnc_argv->pdata, NULL,
+ 0, NULL, NULL, NULL, &error)) {
+ g_ptr_array_free (vpnc_argv, TRUE);
+ error_msg("vpn disconnect failed to start: %s\n", error->message);
+ g_error_free(error);
+ g_free(pid);
+ return FALSE;
+ }
+
+ g_ptr_array_free (vpnc_argv, TRUE);
+ g_free(pid);
+
+ return TRUE;
+}
+
+/* Write out the temporary vpnc config-file */
+gboolean vpnc_config_write(PluginInfo *info)
+{
+ g_debug("Executing %s", __PRETTY_FUNCTION__);
+ FILE *config;
+ char tmp[] = "/tmp/vpnc.XXXXXX";
+
+ PluginInfoPrivate *priv = VPNGUI_PLUGIN_GET_PRIVATE (info);
+
+ if (mkstemp(tmp) < 0) {
+ return FALSE;
+ }
+ priv->vpnc_config = strdup(tmp);
+ config = fopen(priv->vpnc_config, "w+");
+ if (! config) {
+ return FALSE;
+ }
+
+ fprintf(config, "Debug 2\n");
+ fprintf(config, "IPSec gateway %s\n", priv->vpn_settings.gwaddress);
+ fprintf(config, "IPSec ID %s\n", priv->vpn_settings.group);
+ if (priv->vpn_settings.secret_obf) {
+ fprintf(config, "IPSec obfuscated secret %s\n", priv->vpn_settings.secret);
+ } else {
+ fprintf(config, "IPSec secret %s\n", priv->vpn_settings.secret);
+ }
+ fprintf(config, "Xauth username %s\n", priv->vpn_settings.username);
+ fprintf(config, "Xauth password %s\n", priv->vpn_settings.password);
+#ifdef VPNC_0_3_3
+ fprintf(config, "Rekeying interval %d\n", priv->vpn_settings.rekeyinterval);
+ fprintf(config, "NAT-Keepalive packet interval %d\n", priv->vpn_settings.natkeepalive);
+#endif
+ fclose(config);
+ return TRUE;
+}
+// vim:ts=4:sw=4:sts=4