nm: Automatically determine path to the auth dialog
[strongswan.git] / src / frontends / gnome / auth-dialog / main.c
1 /*
2 * Copyright (C) 2008-2011 Martin Willi
3 * Hochschule fuer Technik Rapperswil
4 * Copyright (C) 2004 Dan Williams
5 * Red Hat, Inc.
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 * for more details.
16 */
17
18 #ifdef HAVE_CONFIG_H
19 #include <config.h>
20 #endif
21
22 #include <string.h>
23 #include <glib/gi18n.h>
24 #include <gtk/gtk.h>
25 #include <gnome-keyring.h>
26 #include <libgnomeui/libgnomeui.h>
27 #include <nm-vpn-plugin.h>
28 #include <nm-setting-vpn.h>
29 #include <nm-setting-connection.h>
30 #include <nm-vpn-plugin-utils.h>
31
32 #define NM_DBUS_SERVICE_STRONGSWAN "org.freedesktop.NetworkManager.strongswan"
33
34 /**
35 * lookup a password in the keyring
36 */
37 static char *lookup_password(char *name, char *service)
38 {
39 GList *list;
40 GList *iter;
41 char *pass = NULL;
42
43 if (gnome_keyring_find_network_password_sync(g_get_user_name(), NULL, name,
44 NULL, service, NULL, 0, &list) != GNOME_KEYRING_RESULT_OK)
45 {
46 return NULL;
47 }
48
49 for (iter = list; iter; iter = iter->next)
50 {
51 GnomeKeyringNetworkPasswordData *data = iter->data;
52
53 if (strcmp(data->object, "password") == 0 && data->password)
54 {
55 pass = g_strdup(data->password);
56 break;
57 }
58 }
59 gnome_keyring_network_password_list_free(list);
60 return pass;
61 }
62
63 /**
64 * Wait for quit input
65 */
66 static void wait_for_quit (void)
67 {
68 GString *str;
69 char c;
70 ssize_t n;
71 time_t start;
72
73 str = g_string_sized_new (10);
74 start = time (NULL);
75 do {
76 errno = 0;
77 n = read (0, &c, 1);
78 if (n == 0 || (n < 0 && errno == EAGAIN))
79 g_usleep (G_USEC_PER_SEC / 10);
80 else if (n == 1) {
81 g_string_append_c (str, c);
82 if (strstr (str->str, "QUIT") || (str->len > 10))
83 break;
84 } else
85 break;
86 } while (time (NULL) < start + 20);
87 g_string_free (str, TRUE);
88 }
89
90 /**
91 * get the connection type
92 */
93 static char* get_connection_type(char *uuid)
94 {
95 GHashTable *data = NULL, *secrets = NULL;
96 char *method;
97
98 if (!nm_vpn_plugin_utils_read_vpn_details (0, &data, &secrets)) {
99 fprintf (stderr, "Failed to read data and secrets from stdin.\n");
100 return NULL;
101 }
102
103 method = g_hash_table_lookup (data, "method");
104 if (method)
105 method = g_strdup(method);
106
107 if (data)
108 g_hash_table_unref (data);
109 if (secrets)
110 g_hash_table_unref (secrets);
111
112 return method;
113 }
114
115 int main (int argc, char *argv[])
116 {
117 gboolean retry = FALSE, allow_interaction = FALSE;
118 gchar *name = NULL, *uuid = NULL, *service = NULL, *keyring = NULL, *pass;
119 GOptionContext *context;
120 char *agent, *type;
121 guint32 itemid, minlen = 0;
122 GtkWidget *dialog;
123 GOptionEntry entries[] = {
124 { "reprompt", 'r', 0, G_OPTION_ARG_NONE, &retry, "Reprompt for passwords", NULL},
125 { "uuid", 'u', 0, G_OPTION_ARG_STRING, &uuid, "UUID of VPN connection", NULL},
126 { "name", 'n', 0, G_OPTION_ARG_STRING, &name, "Name of VPN connection", NULL},
127 { "service", 's', 0, G_OPTION_ARG_STRING, &service, "VPN service type", NULL},
128 { "allow-interaction", 'i', 0, G_OPTION_ARG_NONE, &allow_interaction, "Allow user interaction", NULL},
129 { NULL }
130 };
131
132 bindtextdomain(GETTEXT_PACKAGE, NULL);
133 bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
134 textdomain(GETTEXT_PACKAGE);
135
136 gtk_init (&argc, &argv);
137
138 context = g_option_context_new ("- strongswan auth dialog");
139 g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
140 g_option_context_parse (context, &argc, &argv, NULL);
141 g_option_context_free (context);
142
143 if (uuid == NULL || name == NULL || service == NULL)
144 {
145 fprintf (stderr, "Have to supply UUID, name, and service\n");
146 return 1;
147 }
148
149 if (strcmp(service, NM_DBUS_SERVICE_STRONGSWAN) != 0)
150 {
151 fprintf(stderr, "This dialog only works with the '%s' service\n",
152 NM_DBUS_SERVICE_STRONGSWAN);
153 return 1;
154 }
155
156 type = get_connection_type(uuid);
157 if (!type)
158 {
159 fprintf(stderr, "Connection lookup failed\n");
160 return 1;
161 }
162 if (!strcmp(type, "eap") || !strcmp(type, "key") || !strcmp(type, "psk") ||
163 !strcmp(type, "smartcard"))
164 {
165 pass = lookup_password(name, service);
166 if ((!pass || retry) && allow_interaction)
167 {
168 if (!strcmp(type, "eap"))
169 {
170 dialog = gnome_password_dialog_new(_("VPN password required"),
171 _("EAP password required to establish VPN connection:"),
172 NULL, NULL, TRUE);
173 gnome_password_dialog_set_show_remember(GNOME_PASSWORD_DIALOG(dialog), TRUE);
174 }
175 else if (!strcmp(type, "key"))
176 {
177 dialog = gnome_password_dialog_new(_("VPN password required"),
178 _("Private key decryption password required to establish VPN connection:"),
179 NULL, NULL, TRUE);
180 gnome_password_dialog_set_show_remember(GNOME_PASSWORD_DIALOG(dialog), TRUE);
181 }
182 else if (!strcmp(type, "psk"))
183 {
184 dialog = gnome_password_dialog_new(_("VPN password required"),
185 _("Pre-shared key required to establish VPN connection (min. 20 characters):"),
186 NULL, NULL, TRUE);
187 gnome_password_dialog_set_show_remember(GNOME_PASSWORD_DIALOG(dialog), TRUE);
188 minlen = 20;
189 }
190 else /* smartcard */
191 {
192 dialog = gnome_password_dialog_new(_("VPN password required"),
193 _("Smartcard PIN required to establish VPN connection:"),
194 NULL, NULL, TRUE);
195 gnome_password_dialog_set_show_remember(GNOME_PASSWORD_DIALOG(dialog), FALSE);
196 }
197 gnome_password_dialog_set_show_username(GNOME_PASSWORD_DIALOG(dialog), FALSE);
198 if (pass)
199 {
200 gnome_password_dialog_set_password(GNOME_PASSWORD_DIALOG(dialog), pass);
201 }
202
203 too_short_retry:
204 if (!gnome_password_dialog_run_and_block(GNOME_PASSWORD_DIALOG(dialog)))
205 {
206 return 1;
207 }
208
209 pass = gnome_password_dialog_get_password(GNOME_PASSWORD_DIALOG(dialog));
210 if (minlen && strlen(pass) < minlen)
211 {
212 goto too_short_retry;
213 }
214 switch (gnome_password_dialog_get_remember(GNOME_PASSWORD_DIALOG(dialog)))
215 {
216 case GNOME_PASSWORD_DIALOG_REMEMBER_NOTHING:
217 break;
218 case GNOME_PASSWORD_DIALOG_REMEMBER_SESSION:
219 keyring = "session";
220 /* FALL */
221 case GNOME_PASSWORD_DIALOG_REMEMBER_FOREVER:
222 if (gnome_keyring_set_network_password_sync(keyring,
223 g_get_user_name(), NULL, name, "password", service, NULL, 0,
224 pass, &itemid) != GNOME_KEYRING_RESULT_OK)
225 {
226 g_warning ("storing password in keyring failed");
227 }
228 break;
229 }
230 }
231 if (pass)
232 {
233 printf("password\n%s\n", pass);
234 }
235 }
236 else
237 {
238 agent = getenv("SSH_AUTH_SOCK");
239 if (agent)
240 {
241 printf("agent\n%s\n", agent);
242 }
243 else
244 {
245 if (allow_interaction)
246 {
247 dialog = gtk_message_dialog_new(NULL, 0, GTK_MESSAGE_ERROR,
248 GTK_BUTTONS_OK,
249 _("Configuration uses ssh-agent for authentication, "
250 "but ssh-agent is not running!"));
251 gtk_dialog_run (GTK_DIALOG (dialog));
252 gtk_widget_destroy (dialog);
253 }
254 }
255 }
256 printf("\n\n");
257 /* flush output, wait for input */
258 fflush(stdout);
259 wait_for_quit ();
260 return 0;
261 }