Uploaded initial version.
[guivpn] / trunk / vpngui / src / vpnc-util.c
1 /*
2  * This file is part of vpngui
3  *
4  * Copyright © 2009 Nokia Corporation and/or its subsidiary(-ies)
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  * */
20
21 #include <glib.h>
22 #include <stdlib.h>
23 #include <sys/wait.h>
24 #include <string.h>
25 #include <unistd.h>
26
27 #include "vpngui.h"
28
29 /* these are pretty much copy-pasted from networkmanager-vpnc... */
30
31 static void vpnc_watch_cb(GPid pid, gint status, gpointer data)
32 {
33     PluginInfo *info;
34     g_return_if_fail(data);
35     info = (PluginInfo *)data;
36     guint error = -1;
37     gchar *errmsg = NULL;
38         PluginInfoPrivate   *priv = VPNGUI_PLUGIN_GET_PRIVATE (info);
39     gboolean forced_disconnection = (VPN_FORCED_DISCONNECTING == priv->state);
40             
41     g_debug("Executing %s", __PRETTY_FUNCTION__);
42
43     switch(priv->state) {
44         case VPN_CONNECTING:            
45                 /* if we get here during connecting things went foobar... */
46                 set_state(info, VPN_CONNECT_FAILED);
47                 break;
48         case VPN_DISCONNECTING:
49         case VPN_FORCED_DISCONNECTING:  
50                 set_state(info, VPN_DISCONNECTED);
51                 break;
52         case VPN_DISCONNECTED:
53                 break;
54         default:
55                 set_state(info, VPN_DISCONNECTED); 
56     };
57     if(!forced_disconnection) {
58         if (WIFEXITED(status)) {
59                 error = WEXITSTATUS(status);
60                 if (error != 0) {
61
62                 // Nasty hack: vpnc 0.5.1 returns with code 256 on erroneous auth.
63                 // but maybe it returns with 256 on other cases to.
64                 /// @todo Check vpnc errorcodes.
65                         if ( status == 256 ) errmsg = NULL;//g_strdup_printf("Authentication failed");
66                         else 
67                         errmsg = g_strdup_printf("Vpnc exited with error code %d\n", status);
68
69                 }
70         } else if (WIFSTOPPED(status)) {
71                 errmsg = g_strdup_printf("Vpnc was stopped unexpectedly");
72         } else if (WIFSIGNALED(status)) {
73                 errmsg = g_strdup_printf("Vpnc died from signal %d", WTERMSIG (status));
74         } else {
75                 errmsg = g_strdup_printf("Vpnc died under suspicious circumstances");
76         }
77     };  
78         g_spawn_close_pid(priv->vpnc_pid);      
79
80         priv->vpnc_pid = 0;
81
82         switch (error) {
83                 case 2:
84                         error_msg("Authentication failed");
85                         break;
86                 case 1:
87                         if (errmsg)
88                                 error_msg("Error:\n%s", errmsg);
89                         break;
90                 default:
91                         break;
92         }
93         if (errmsg) {
94                 g_free(errmsg);
95         }
96
97    g_debug("Exiting %s", __PRETTY_FUNCTION__);          
98 }
99
100 gboolean vpnc_start(PluginInfo *info)
101 {
102         GPid pid;
103         GPtrArray *vpnc_argv;
104         GError *error = NULL;
105         GSource *vpnc_watch;
106         gint stdin_fd = -1;
107         g_debug("Executing %s", __PRETTY_FUNCTION__);
108
109         g_return_val_if_fail (info != NULL, FALSE);
110         
111         PluginInfoPrivate   *priv = VPNGUI_PLUGIN_GET_PRIVATE (info);
112
113         priv->vpnc_pid = 0;
114
115         vpnc_argv = g_ptr_array_new();
116         g_ptr_array_add (vpnc_argv, (gpointer) "/usr/bin/sudo");
117         g_ptr_array_add (vpnc_argv, (gpointer) "/usr/sbin/vpngui-helper");
118         g_ptr_array_add (vpnc_argv, (gpointer) "connect");
119         g_ptr_array_add (vpnc_argv, (gpointer) "--non-inter");
120         g_ptr_array_add (vpnc_argv, (gpointer) "--no-detach");
121         g_ptr_array_add (vpnc_argv, (gpointer) priv->vpnc_config);
122         g_ptr_array_add (vpnc_argv, NULL);
123
124         if (!g_spawn_async_with_pipes (NULL, (char **) vpnc_argv->pdata, NULL,
125                                         G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &pid, &stdin_fd,
126                                         NULL, NULL, &error)) {
127                 g_ptr_array_free (vpnc_argv, TRUE);
128                 error_msg("vpnc failed to start: %s\n", error->message);
129                 g_error_free(error);
130             return FALSE;
131         }
132
133     g_ptr_array_free (vpnc_argv, TRUE);
134
135     g_debug("%s: vpnc started with pid %d", __PRETTY_FUNCTION__, pid);
136     set_state(info, VPN_CONNECTING);
137
138     vpnc_watch = g_child_watch_source_new (pid);
139     g_source_set_callback (vpnc_watch, (GSourceFunc) vpnc_watch_cb, info, NULL);
140
141     g_source_attach (vpnc_watch, NULL);
142
143     priv->vpnc_pid = pid;
144     priv->vpnc_watch_id = g_source_get_id(vpnc_watch);
145
146     g_source_unref (vpnc_watch);
147     g_debug("Exiting %s", __PRETTY_FUNCTION__);
148     return TRUE;
149 }
150
151 /*
152  * start the vpnc killer - we'll get notified of vpnc actually
153  * dying elsewhere so we don't care about the results here
154  */
155 gboolean vpnc_stop(PluginInfo *info, const gboolean forced)
156 {
157         GPtrArray *vpnc_argv;
158         GError *error = NULL;
159         gchar *pid;
160
161         g_debug("Executing %s, forced = %d", __PRETTY_FUNCTION__, forced);      
162
163         g_return_val_if_fail (info != NULL, FALSE);
164         PluginInfoPrivate   *priv = VPNGUI_PLUGIN_GET_PRIVATE (info);
165
166         if (priv->vpnc_pid == 0) {
167                 return TRUE;
168         }
169
170         pid = g_strdup_printf("%d", priv->vpnc_pid);
171
172         vpnc_argv = g_ptr_array_new();
173         g_ptr_array_add (vpnc_argv, (gpointer) "/usr/bin/sudo");
174         g_ptr_array_add (vpnc_argv, (gpointer) "/usr/sbin/vpngui-helper");
175         g_ptr_array_add (vpnc_argv, (gpointer) "disconnect");
176         g_ptr_array_add (vpnc_argv, (gpointer) pid);
177         g_ptr_array_add (vpnc_argv, NULL);
178
179         if (!g_spawn_async(NULL, (char **) vpnc_argv->pdata, NULL,
180                                 0, NULL, NULL, NULL, &error)) {
181                         g_ptr_array_free (vpnc_argv, TRUE);
182                         error_msg("vpn disconnect failed to start: %s\n", error->message);
183                         g_error_free(error);
184                         g_free(pid);
185                         return FALSE;
186         }
187         set_state(info, forced ? VPN_FORCED_DISCONNECTING : VPN_DISCONNECTING);
188
189         /* unregister the vpnc watcher, we'll get notified by dbus on disconnect */
190 //      g_source_remove(info->vpnc_watch_id);
191 //      info->vpnc_watch_id = 0;
192
193         g_ptr_array_free (vpnc_argv, TRUE);
194         g_free(pid);
195
196         return TRUE;
197 }
198
199 gboolean vpnc_restart(PluginInfo *info)
200 {
201         GPtrArray *vpnc_argv;
202         GError *error = NULL;
203         gchar *pid;
204
205         g_debug("Executing %s", __PRETTY_FUNCTION__);
206
207         g_return_val_if_fail (info != NULL, FALSE);
208         PluginInfoPrivate   *priv = VPNGUI_PLUGIN_GET_PRIVATE (info);
209
210         if (priv->vpnc_pid == 0) {
211                 return TRUE;
212         }
213
214         pid = g_strdup_printf("%d", priv->vpnc_pid);
215
216         vpnc_argv = g_ptr_array_new();
217         g_ptr_array_add (vpnc_argv, (gpointer) "/usr/bin/sudo");
218         g_ptr_array_add (vpnc_argv, (gpointer) "/usr/sbin/vpngui-helper");
219         g_ptr_array_add (vpnc_argv, (gpointer) "reconnect");
220         g_ptr_array_add (vpnc_argv, (gpointer) pid);
221         g_ptr_array_add (vpnc_argv, NULL);
222
223         if (!g_spawn_async(NULL, (char **) vpnc_argv->pdata, NULL,
224                                 0, NULL, NULL, NULL, &error)) {
225                         g_ptr_array_free (vpnc_argv, TRUE);
226                         error_msg("vpn disconnect failed to start: %s\n", error->message);
227                         g_error_free(error);
228                         g_free(pid);
229                         return FALSE;
230         }
231
232         g_ptr_array_free (vpnc_argv, TRUE);
233         g_free(pid);
234
235         return TRUE;
236 }
237
238 /* Write out the temporary vpnc config-file */
239 gboolean vpnc_config_write(PluginInfo *info)
240 {
241         g_debug("Executing %s", __PRETTY_FUNCTION__);   
242         FILE *config;
243         char tmp[] = "/tmp/vpnc.XXXXXX";
244
245         PluginInfoPrivate   *priv = VPNGUI_PLUGIN_GET_PRIVATE (info);
246
247         if (mkstemp(tmp) < 0) {
248                 return FALSE;
249         }
250         priv->vpnc_config = strdup(tmp);
251         config = fopen(priv->vpnc_config, "w+");
252         if (! config) {
253                 return FALSE;
254         }
255
256         fprintf(config, "Debug 2\n");
257         fprintf(config, "IPSec gateway %s\n", priv->vpn_settings.gwaddress);
258         fprintf(config, "IPSec ID %s\n", priv->vpn_settings.group);
259         if (priv->vpn_settings.secret_obf) {
260                 fprintf(config, "IPSec obfuscated secret %s\n", priv->vpn_settings.secret);
261         } else {
262                 fprintf(config, "IPSec secret %s\n", priv->vpn_settings.secret);
263         }
264         fprintf(config, "Xauth username %s\n", priv->vpn_settings.username);
265         fprintf(config, "Xauth password %s\n", priv->vpn_settings.password);
266 #ifdef VPNC_0_3_3
267         fprintf(config, "Rekeying interval %d\n", priv->vpn_settings.rekeyinterval);
268         fprintf(config, "NAT-Keepalive packet interval %d\n", priv->vpn_settings.natkeepalive);
269 #endif
270         fclose(config);
271         return TRUE;
272 }
273 // vim:ts=4:sw=4:sts=4