nm: Replace libgnomekeyring with libsecret
[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 <libsecret/secret.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 * Wait for quit input
36 */
37 static void wait_for_quit (void)
38 {
39 GString *str;
40 char c;
41 ssize_t n;
42 time_t start;
43
44 str = g_string_sized_new (10);
45 start = time (NULL);
46 do {
47 errno = 0;
48 n = read (0, &c, 1);
49 if (n == 0 || (n < 0 && errno == EAGAIN))
50 g_usleep (G_USEC_PER_SEC / 10);
51 else if (n == 1) {
52 g_string_append_c (str, c);
53 if (strstr (str->str, "QUIT") || (str->len > 10))
54 break;
55 } else
56 break;
57 } while (time (NULL) < start + 20);
58 g_string_free (str, TRUE);
59 }
60
61 /**
62 * get the connection type
63 */
64 static char* get_connection_type(char *uuid)
65 {
66 GHashTable *data = NULL, *secrets = NULL;
67 char *method;
68
69 if (!nm_vpn_plugin_utils_read_vpn_details (0, &data, &secrets)) {
70 fprintf (stderr, "Failed to read data and secrets from stdin.\n");
71 return NULL;
72 }
73
74 method = g_hash_table_lookup (data, "method");
75 if (method)
76 method = g_strdup(method);
77
78 if (data)
79 g_hash_table_unref (data);
80 if (secrets)
81 g_hash_table_unref (secrets);
82
83 return method;
84 }
85
86 int main (int argc, char *argv[])
87 {
88 gboolean retry = FALSE, allow_interaction = FALSE;
89 gchar *name = NULL, *uuid = NULL, *service = NULL, *keyring = NULL, *pass;
90 GOptionContext *context;
91 char *agent, *type;
92 guint32 minlen = 0;
93 GtkWidget *dialog;
94 GOptionEntry entries[] = {
95 { "reprompt", 'r', 0, G_OPTION_ARG_NONE, &retry, "Reprompt for passwords", NULL},
96 { "uuid", 'u', 0, G_OPTION_ARG_STRING, &uuid, "UUID of VPN connection", NULL},
97 { "name", 'n', 0, G_OPTION_ARG_STRING, &name, "Name of VPN connection", NULL},
98 { "service", 's', 0, G_OPTION_ARG_STRING, &service, "VPN service type", NULL},
99 { "allow-interaction", 'i', 0, G_OPTION_ARG_NONE, &allow_interaction, "Allow user interaction", NULL},
100 { NULL }
101 };
102
103 bindtextdomain(GETTEXT_PACKAGE, NULL);
104 bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
105 textdomain(GETTEXT_PACKAGE);
106
107 gtk_init (&argc, &argv);
108
109 context = g_option_context_new ("- strongswan auth dialog");
110 g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
111 g_option_context_parse (context, &argc, &argv, NULL);
112 g_option_context_free (context);
113
114 if (uuid == NULL || name == NULL || service == NULL)
115 {
116 fprintf (stderr, "Have to supply UUID, name, and service\n");
117 return 1;
118 }
119
120 if (strcmp(service, NM_DBUS_SERVICE_STRONGSWAN) != 0)
121 {
122 fprintf(stderr, "This dialog only works with the '%s' service\n",
123 NM_DBUS_SERVICE_STRONGSWAN);
124 return 1;
125 }
126
127 type = get_connection_type(uuid);
128 if (!type)
129 {
130 fprintf(stderr, "Connection lookup failed\n");
131 return 1;
132 }
133 if (!strcmp(type, "eap") || !strcmp(type, "key") || !strcmp(type, "psk") ||
134 !strcmp(type, "smartcard"))
135 {
136 pass = secret_password_lookup_sync(SECRET_SCHEMA_COMPAT_NETWORK, NULL, NULL,
137 "user", g_get_user_name(),
138 "server", name,
139 "protocol", service,
140 NULL);
141
142 if ((!pass || retry) && allow_interaction)
143 {
144 if (!strcmp(type, "eap"))
145 {
146 dialog = gnome_password_dialog_new(_("VPN password required"),
147 _("EAP password required to establish VPN connection:"),
148 NULL, NULL, TRUE);
149 gnome_password_dialog_set_show_remember(GNOME_PASSWORD_DIALOG(dialog), TRUE);
150 }
151 else if (!strcmp(type, "key"))
152 {
153 dialog = gnome_password_dialog_new(_("VPN password required"),
154 _("Private key decryption password required to establish VPN connection:"),
155 NULL, NULL, TRUE);
156 gnome_password_dialog_set_show_remember(GNOME_PASSWORD_DIALOG(dialog), TRUE);
157 }
158 else if (!strcmp(type, "psk"))
159 {
160 dialog = gnome_password_dialog_new(_("VPN password required"),
161 _("Pre-shared key required to establish VPN connection (min. 20 characters):"),
162 NULL, NULL, TRUE);
163 gnome_password_dialog_set_show_remember(GNOME_PASSWORD_DIALOG(dialog), TRUE);
164 minlen = 20;
165 }
166 else /* smartcard */
167 {
168 dialog = gnome_password_dialog_new(_("VPN password required"),
169 _("Smartcard PIN required to establish VPN connection:"),
170 NULL, NULL, TRUE);
171 gnome_password_dialog_set_show_remember(GNOME_PASSWORD_DIALOG(dialog), FALSE);
172 }
173 gnome_password_dialog_set_show_username(GNOME_PASSWORD_DIALOG(dialog), FALSE);
174 if (pass)
175 {
176 gnome_password_dialog_set_password(GNOME_PASSWORD_DIALOG(dialog), pass);
177 }
178
179 too_short_retry:
180 if (!gnome_password_dialog_run_and_block(GNOME_PASSWORD_DIALOG(dialog)))
181 {
182 return 1;
183 }
184
185 pass = gnome_password_dialog_get_password(GNOME_PASSWORD_DIALOG(dialog));
186 if (minlen && strlen(pass) < minlen)
187 {
188 goto too_short_retry;
189 }
190 switch (gnome_password_dialog_get_remember(GNOME_PASSWORD_DIALOG(dialog)))
191 {
192 case GNOME_PASSWORD_DIALOG_REMEMBER_NOTHING:
193 break;
194 case GNOME_PASSWORD_DIALOG_REMEMBER_SESSION:
195 keyring = SECRET_COLLECTION_SESSION;
196 /* FALL */
197 case GNOME_PASSWORD_DIALOG_REMEMBER_FOREVER:
198 if (!secret_password_store_sync(SECRET_SCHEMA_COMPAT_NETWORK,
199 keyring, "", pass, NULL, NULL,
200 "user", g_get_user_name(),
201 "server", name,
202 "protocol", service,
203 NULL))
204 {
205 g_warning ("storing password in keyring failed");
206 }
207 break;
208 }
209 }
210 if (pass)
211 {
212 printf("password\n%s\n", pass);
213 g_free(pass);
214 }
215 }
216 else
217 {
218 agent = getenv("SSH_AUTH_SOCK");
219 if (agent)
220 {
221 printf("agent\n%s\n", agent);
222 }
223 else
224 {
225 if (allow_interaction)
226 {
227 dialog = gtk_message_dialog_new(NULL, 0, GTK_MESSAGE_ERROR,
228 GTK_BUTTONS_OK,
229 _("Configuration uses ssh-agent for authentication, "
230 "but ssh-agent is not running!"));
231 gtk_dialog_run (GTK_DIALOG (dialog));
232 gtk_widget_destroy (dialog);
233 }
234 }
235 }
236 printf("\n\n");
237 /* flush output, wait for input */
238 fflush(stdout);
239 wait_for_quit ();
240 return 0;
241 }