]> git.ipfire.org Git - thirdparty/strongswan.git/blame - src/frontends/gnome/auth-dialog/main.c
Update copyright headers after acquisition by secunet
[thirdparty/strongswan.git] / src / frontends / gnome / auth-dialog / main.c
CommitLineData
ec249871 1/*
47bd094e
LR
2 * Copyright (C) 2015 Lubomir Rintel
3 *
be1061c9 4 * Copyright (C) 2013-2016 Tobias Brunner
791c93f3 5 * Copyright (C) 2008-2011 Martin Willi
47bd094e 6 *
7daf5226 7 * Copyright (C) 2004 Dan Williams
592dc301 8 * Red Hat, Inc.
ec249871
MW
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2 of the License, or (at your
13 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
14 *
15 * This program is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
17 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 * for more details.
ec249871
MW
19 */
20
21#ifdef HAVE_CONFIG_H
22#include <config.h>
23#endif
24
47bd094e
LR
25#include <errno.h>
26#include <stdlib.h>
ec249871
MW
27#include <string.h>
28#include <glib/gi18n.h>
29#include <gtk/gtk.h>
a88831a0 30#include <libsecret/secret.h>
ae8082da
LR
31
32#include <NetworkManager.h>
33#include <nm-vpn-service-plugin.h>
47bd094e 34#include <nma-vpn-password-dialog.h>
ec249871 35
aff26a62 36#define NM_DBUS_SERVICE_STRONGSWAN "org.freedesktop.NetworkManager.strongswan"
ec249871 37
be1061c9
TB
38#define KEYRING_UUID_TAG "connection-uuid"
39#define KEYRING_SN_TAG "setting-name"
40#define KEYRING_SK_TAG "setting-key"
41
42static const SecretSchema network_manager_secret_schema = {
43 "org.freedesktop.NetworkManager.Connection",
44 SECRET_SCHEMA_DONT_MATCH_NAME,
45 {
46 { KEYRING_UUID_TAG, SECRET_SCHEMA_ATTRIBUTE_STRING },
47 { KEYRING_SN_TAG, SECRET_SCHEMA_ATTRIBUTE_STRING },
48 { KEYRING_SK_TAG, SECRET_SCHEMA_ATTRIBUTE_STRING },
49 { NULL, 0 },
50 }
51};
52
53#define UI_KEYFILE_GROUP "VPN Plugin UI"
54
55static char *keyring_lookup_secret(const char *uuid, const char *secret_name)
56{
57 GHashTable *attrs;
58 GList *list;
59 char *secret = NULL;
60
61 attrs = secret_attributes_build(&network_manager_secret_schema,
62 KEYRING_UUID_TAG, uuid,
63 KEYRING_SN_TAG, NM_SETTING_VPN_SETTING_NAME,
64 KEYRING_SK_TAG, secret_name,
65 NULL);
66
67 list = secret_service_search_sync (NULL, &network_manager_secret_schema, attrs,
68 SECRET_SEARCH_ALL | SECRET_SEARCH_UNLOCK | SECRET_SEARCH_LOAD_SECRETS,
69 NULL, NULL);
70 if (list && list->data)
71 {
72 SecretItem *item = list->data;
73 SecretValue *value = secret_item_get_secret (item);
74
75 if (value)
76 {
77 secret = g_strdup (secret_value_get (value, NULL));
78 secret_value_unref (value);
79 }
80 }
81
82 g_list_free_full (list, g_object_unref);
83 g_hash_table_unref (attrs);
84 return secret;
85}
86
87static void keyfile_add_entry_info(GKeyFile *keyfile, const gchar *key, const gchar *value,
88 const gchar *label, gboolean is_secret, gboolean should_ask)
89{
90 g_key_file_set_string (keyfile, key, "Value", value);
91 g_key_file_set_string (keyfile, key, "Label", label);
92 g_key_file_set_boolean (keyfile, key, "IsSecret", is_secret);
93 g_key_file_set_boolean (keyfile, key, "ShouldAsk", should_ask);
94}
95
96static void keyfile_print_stdout (GKeyFile *keyfile)
97{
98 gchar *data;
99 gsize length;
100
101 data = g_key_file_to_data (keyfile, &length, NULL);
102
103 fputs (data, stdout);
104
105 g_free (data);
106}
107
661e1044
TB
108static gboolean get_secrets(const char *type, const char *cert_source, const char *uuid, const char *name,
109 gboolean retry, gboolean allow_interaction, gboolean external_ui_mode,
be1061c9
TB
110 const char *in_pw, char **out_pw, NMSettingSecretFlags flags)
111{
112 NMAVpnPasswordDialog *dialog;
113 char *prompt, *pw = NULL;
114 const char *new_pw = NULL;
115 guint32 minlen = 0;
116
117 if (!(flags & NM_SETTING_SECRET_FLAG_NOT_SAVED) &&
118 !(flags & NM_SETTING_SECRET_FLAG_NOT_REQUIRED))
119 {
120 if (in_pw)
121 {
122 pw = g_strdup (in_pw);
123 }
124 else
125 {
126 pw = keyring_lookup_secret (uuid, "password");
127 }
128 }
129 if (flags & NM_SETTING_SECRET_FLAG_NOT_REQUIRED)
130 {
131 g_free (pw);
132 return TRUE;
133 }
134 if (!strcmp(type, "eap"))
135 {
136 prompt = g_strdup_printf (_("EAP password required to establish VPN connection '%s'."),
137 name);
138 }
be1061c9
TB
139 else if (!strcmp(type, "psk"))
140 {
141 prompt = g_strdup_printf (_("Pre-shared key required to establish VPN connection '%s' (min. 20 characters)."),
142 name);
143 minlen = 20;
144 }
661e1044 145 else /* certificate auth of some kind */
be1061c9 146 {
661e1044
TB
147 if (!strcmp(cert_source, "smartcard"))
148 {
149 prompt = g_strdup_printf (_("Smartcard PIN required to establish VPN connection '%s'."),
150 name);
151 }
152 else
153 {
154 prompt = g_strdup_printf (_("Private key decryption password required to establish VPN connection '%s'."),
155 name);
156 }
be1061c9
TB
157 }
158 if (external_ui_mode)
159 {
160 GKeyFile *keyfile;
161
162 keyfile = g_key_file_new ();
163
164 g_key_file_set_integer (keyfile, UI_KEYFILE_GROUP, "Version", 2);
165 g_key_file_set_string (keyfile, UI_KEYFILE_GROUP, "Description", prompt);
166 g_key_file_set_string (keyfile, UI_KEYFILE_GROUP, "Title", _("Authenticate VPN"));
167
168 keyfile_add_entry_info (keyfile, "password", pw ?: "", _("Password:"), TRUE, allow_interaction);
169
170 keyfile_print_stdout (keyfile);
171 g_key_file_unref (keyfile);
172 goto out;
173 }
174 else if (!allow_interaction ||
175 (!retry && pw && !(flags & NM_SETTING_SECRET_FLAG_NOT_SAVED)))
176 {
177 /* If we can't prompt the user, just return the existing password. Do the same
178 * if we don't nee a new password (!retry) and have an existing saved one */
179 *out_pw = pw;
180 g_free (prompt);
181 return TRUE;
182 }
183
184 dialog = (NMAVpnPasswordDialog*)nma_vpn_password_dialog_new(_("Authenticate VPN"), prompt, NULL);
185 nma_vpn_password_dialog_set_show_password_secondary(dialog, FALSE);
186
187 if (pw && !(flags & NM_SETTING_SECRET_FLAG_NOT_SAVED))
188 {
189 nma_vpn_password_dialog_set_password(dialog, pw);
190 }
191 gtk_widget_show (GTK_WIDGET (dialog));
192
193too_short_retry:
194 if (nma_vpn_password_dialog_run_and_block (dialog))
195 {
196 new_pw = nma_vpn_password_dialog_get_password(dialog);
197 if (new_pw && minlen && strlen(new_pw) < minlen)
198 {
199 goto too_short_retry;
200 }
201 else if (new_pw)
202 {
203 *out_pw = g_strdup (new_pw);
204 }
205 }
206 gtk_widget_hide (GTK_WIDGET (dialog));
207 gtk_widget_destroy (GTK_WIDGET (dialog));
208out:
209 g_free (prompt);
210 return TRUE;
211}
212
213static void print_secret (const char *secret_name, gchar *secret)
214{
215 if (secret)
216 {
217 printf("%s\n%s\n", secret_name, secret);
218 g_free(secret);
219 }
220 printf("\n\n");
221 fflush(stdout);
222}
223
791c93f3
MW
224static void wait_for_quit (void)
225{
226 GString *str;
227 char c;
228 ssize_t n;
229 time_t start;
230
231 str = g_string_sized_new (10);
232 start = time (NULL);
233 do {
234 errno = 0;
235 n = read (0, &c, 1);
236 if (n == 0 || (n < 0 && errno == EAGAIN))
237 g_usleep (G_USEC_PER_SEC / 10);
238 else if (n == 1) {
239 g_string_append_c (str, c);
240 if (strstr (str->str, "QUIT") || (str->len > 10))
241 break;
242 } else
243 break;
244 } while (time (NULL) < start + 20);
245 g_string_free (str, TRUE);
246}
247
ec249871
MW
248int main (int argc, char *argv[])
249{
be1061c9 250 gboolean retry = FALSE, allow_interaction = FALSE, external_ui_mode = FALSE;
661e1044 251 gboolean need_secret = FALSE;
be1061c9
TB
252 gchar *name = NULL, *uuid = NULL, *service = NULL, *pass = NULL;
253 GHashTable *data = NULL, *secrets = NULL;
254 NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE;
ec249871 255 GOptionContext *context;
661e1044 256 char *agent, *type, *cert_source;
be1061c9 257 int status = 0;
ec249871
MW
258 GOptionEntry entries[] = {
259 { "reprompt", 'r', 0, G_OPTION_ARG_NONE, &retry, "Reprompt for passwords", NULL},
f061d833 260 { "uuid", 'u', 0, G_OPTION_ARG_STRING, &uuid, "UUID of VPN connection", NULL},
ec249871
MW
261 { "name", 'n', 0, G_OPTION_ARG_STRING, &name, "Name of VPN connection", NULL},
262 { "service", 's', 0, G_OPTION_ARG_STRING, &service, "VPN service type", NULL},
791c93f3 263 { "allow-interaction", 'i', 0, G_OPTION_ARG_NONE, &allow_interaction, "Allow user interaction", NULL},
be1061c9 264 { "external-ui-mode", 0, 0, G_OPTION_ARG_NONE, &external_ui_mode, "External UI mode", NULL},
ec249871
MW
265 { NULL }
266 };
267
268 bindtextdomain(GETTEXT_PACKAGE, NULL);
269 bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
270 textdomain(GETTEXT_PACKAGE);
271
791c93f3
MW
272 gtk_init (&argc, &argv);
273
ec249871
MW
274 context = g_option_context_new ("- strongswan auth dialog");
275 g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
791c93f3
MW
276 g_option_context_parse (context, &argc, &argv, NULL);
277 g_option_context_free (context);
7daf5226 278
f061d833 279 if (uuid == NULL || name == NULL || service == NULL)
ec249871 280 {
f061d833 281 fprintf (stderr, "Have to supply UUID, name, and service\n");
ec249871 282 return 1;
f061d833 283 }
7daf5226 284
ec249871
MW
285 if (strcmp(service, NM_DBUS_SERVICE_STRONGSWAN) != 0)
286 {
287 fprintf(stderr, "This dialog only works with the '%s' service\n",
288 NM_DBUS_SERVICE_STRONGSWAN);
ec249871
MW
289 return 1;
290 }
7daf5226 291
be1061c9 292 if (!nm_vpn_service_plugin_read_vpn_details (0, &data, &secrets))
1d03954a 293 {
be1061c9
TB
294 fprintf(stderr, "Failed to read '%s' (%s) data and secrets from stdin.\n",
295 name, uuid);
1d03954a
MW
296 return 1;
297 }
be1061c9
TB
298
299 type = g_hash_table_lookup (data, "method");
300 if (!type)
ec249871 301 {
be1061c9
TB
302 fprintf(stderr, "Connection lookup failed\n");
303 status = 1;
304 goto out;
305 }
661e1044 306 cert_source = g_hash_table_lookup (data, "cert-source") ?: type;
a88831a0 307
661e1044
TB
308 if (!strcmp(type, "cert") ||
309 !strcmp(type, "eap-tls") ||
310 !strcmp(type, "key") ||
311 !strcmp(type, "agent") ||
312 !strcmp(type, "smartcard"))
be1061c9 313 {
661e1044 314 if (!strcmp(cert_source, "agent"))
ec249871 315 {
661e1044
TB
316 agent = getenv("SSH_AUTH_SOCK");
317 if (agent)
318 {
319 if (external_ui_mode)
320 {
321 GKeyFile *keyfile;
322
323 keyfile = g_key_file_new ();
324
325 g_key_file_set_integer (keyfile, UI_KEYFILE_GROUP, "Version", 2);
326 g_key_file_set_string (keyfile, UI_KEYFILE_GROUP, "Description", "SSH agent");
327 g_key_file_set_string (keyfile, UI_KEYFILE_GROUP, "Title", _("Authenticate VPN"));
328
329 keyfile_add_entry_info (keyfile, "agent", agent, "SSH agent socket", TRUE, FALSE);
330
331 keyfile_print_stdout (keyfile);
332 g_key_file_unref (keyfile);
333 }
334 else
335 {
336 print_secret("agent", g_strdup (agent));
337 wait_for_quit ();
338 }
339 }
340 else if (allow_interaction)
341 {
342 GtkWidget *dialog;
343 dialog = gtk_message_dialog_new(NULL, 0, GTK_MESSAGE_ERROR,
344 GTK_BUTTONS_OK,
345 _("Configuration uses ssh-agent for authentication, "
346 "but ssh-agent is not running!"));
347 gtk_dialog_run (GTK_DIALOG (dialog));
348 gtk_widget_destroy (dialog);
349 }
ec249871 350 }
661e1044 351 else
791c93f3 352 {
661e1044 353 need_secret = TRUE;
791c93f3 354 }
aff26a62 355 }
661e1044
TB
356
357 if (need_secret ||
358 !strcmp(type, "eap") ||
359 !strcmp(type, "psk"))
aff26a62 360 {
661e1044
TB
361 nm_vpn_service_plugin_get_secret_flags (secrets, "password", &flags);
362 if (!get_secrets(type, cert_source, uuid, name, retry, allow_interaction,
363 external_ui_mode, g_hash_table_lookup (secrets, "password"), &pass, flags))
ec249871 364 {
661e1044 365 status = 1;
ec249871 366 }
661e1044 367 else if (!external_ui_mode)
be1061c9 368 {
661e1044
TB
369 print_secret("password", pass);
370 wait_for_quit ();
be1061c9 371 }
ec249871 372 }
be1061c9
TB
373
374out:
375 if (data)
376 {
377 g_hash_table_unref (data);
378 }
379 if (secrets)
380 {
381 g_hash_table_unref(secrets);
382 }
383 return status;
ec249871 384}