Uploaded initial version.
[guivpn] / trunk / vpngui / src / vpnc-util.c
diff --git a/trunk/vpngui/src/vpnc-util.c b/trunk/vpngui/src/vpnc-util.c
new file mode 100644 (file)
index 0000000..6d16c79
--- /dev/null
@@ -0,0 +1,273 @@
+/*
+ * 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