Line data Source code
1 : /*
2 : * gnome-keyring
3 : *
4 : * Copyright (C) 2018 Red Hat, Inc.
5 : *
6 : * This program is free software; you can redistribute it and/or modify
7 : * it under the terms of the GNU Lesser General Public License as
8 : * published by the Free Software Foundation; either version 2.1 of
9 : * the License, or (at your option) any later version.
10 : *
11 : * This program is distributed in the hope that it will be useful, but
12 : * WITHOUT ANY WARRANTY; without even the implied warranty of
13 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : * Lesser General Public License for more details.
15 : *
16 : * You should have received a copy of the GNU Lesser General Public
17 : * License along with this program; if not, see
18 : * <http://www.gnu.org/licenses/>.
19 : *
20 : * Author: Daiki Ueno
21 : */
22 :
23 : #include "config.h"
24 :
25 : #include "gkd-ssh-agent-interaction.h"
26 : #include "gkd-ssh-agent-private.h"
27 : #include "daemon/login/gkd-login-password.h"
28 :
29 : #include <gcr/gcr-base.h>
30 : #include <glib/gi18n-lib.h>
31 :
32 : enum {
33 : PROP_0,
34 : PROP_PROMPTER_NAME
35 : };
36 :
37 : struct _GkdSshAgentInteraction {
38 : GTlsInteraction interaction;
39 : gchar *prompter_name;
40 : };
41 :
42 0 : G_DEFINE_TYPE (GkdSshAgentInteraction, gkd_ssh_agent_interaction, G_TYPE_TLS_INTERACTION);
43 :
44 : static void
45 0 : gkd_ssh_agent_interaction_init (GkdSshAgentInteraction *self)
46 : {
47 0 : }
48 :
49 : static void
50 0 : on_prompt_password (GObject *source_object,
51 : GAsyncResult *result,
52 : gpointer user_data)
53 : {
54 0 : GTask *task = G_TASK (user_data);
55 0 : GTlsPassword *password = g_task_get_task_data (task);
56 0 : GkdLoginPassword *login_password = GKD_LOGIN_PASSWORD (password);
57 0 : GcrPrompt *prompt = GCR_PROMPT (source_object);
58 0 : GError *error = NULL;
59 : const gchar *value;
60 :
61 0 : value = gcr_prompt_password_finish (prompt, result, &error);
62 0 : if (!value) {
63 0 : g_object_unref (prompt);
64 0 : if (error)
65 0 : g_task_return_error (task, error);
66 : else
67 0 : g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_CANCELLED, "cancelled");
68 0 : g_object_unref (task);
69 0 : return;
70 : }
71 0 : g_tls_password_set_value (password, (const guchar *)value, strlen (value));
72 0 : gkd_login_password_set_store_password (login_password,
73 : gcr_prompt_get_choice_chosen (prompt));
74 0 : g_object_unref (prompt);
75 :
76 0 : g_task_return_int (task, G_TLS_INTERACTION_HANDLED);
77 0 : g_object_unref (task);
78 : }
79 :
80 : static void
81 0 : on_prompt_open (GObject *source_object,
82 : GAsyncResult *result,
83 : gpointer user_data)
84 : {
85 0 : GTask *task = G_TASK (user_data);
86 0 : GTlsPassword *password = g_task_get_task_data (task);
87 0 : GkdLoginPassword *login_password = GKD_LOGIN_PASSWORD (password);
88 0 : GError *error = NULL;
89 : GcrPrompt *prompt;
90 : const gchar *choice;
91 : gchar *text;
92 :
93 0 : prompt = gcr_system_prompt_open_finish (result, &error);
94 0 : if (!prompt) {
95 0 : g_task_return_error (task, error);
96 0 : g_object_unref (task);
97 0 : return;
98 : }
99 :
100 0 : gcr_prompt_set_title (prompt, _("Unlock private key"));
101 0 : gcr_prompt_set_message (prompt, _("Enter password to unlock the private key"));
102 :
103 : /* TRANSLATORS: The private key is locked */
104 0 : text = g_strdup_printf (_("An application wants access to the private key “%s”, but it is locked"),
105 : g_tls_password_get_description (password));
106 0 : gcr_prompt_set_description (prompt, text);
107 0 : g_free (text);
108 :
109 0 : choice = NULL;
110 0 : if (gkd_login_password_get_login_available (login_password))
111 0 : choice = _("Automatically unlock this key whenever I’m logged in");
112 0 : gcr_prompt_set_choice_label (prompt, choice);
113 0 : gcr_prompt_set_continue_label (prompt, _("Unlock"));
114 :
115 0 : if (g_tls_password_get_flags (password) & G_TLS_PASSWORD_RETRY)
116 0 : gcr_prompt_set_warning (prompt, _("The unlock password was incorrect"));
117 :
118 0 : gcr_prompt_password_async (prompt, g_task_get_cancellable (task), on_prompt_password, task);
119 : }
120 :
121 : static void
122 0 : gkd_ssh_agent_interaction_ask_password_async (GTlsInteraction *interaction,
123 : GTlsPassword *password,
124 : GCancellable *cancellable,
125 : GAsyncReadyCallback callback,
126 : gpointer user_data)
127 : {
128 0 : GkdSshAgentInteraction *self = GKD_SSH_AGENT_INTERACTION (interaction);
129 : GTask *task;
130 :
131 0 : task = g_task_new (interaction, cancellable, callback, user_data);
132 0 : g_task_set_task_data (task, g_object_ref (password), g_object_unref);
133 :
134 0 : gcr_system_prompt_open_for_prompter_async (self->prompter_name, 60,
135 : cancellable,
136 : on_prompt_open,
137 : task);
138 0 : }
139 :
140 : static GTlsInteractionResult
141 0 : gkd_ssh_agent_interaction_ask_password_finish (GTlsInteraction *interaction,
142 : GAsyncResult *res,
143 : GError **error)
144 : {
145 0 : GTask *task = G_TASK (res);
146 : GTlsInteractionResult result;
147 :
148 0 : result = g_task_propagate_int (task, error);
149 0 : if (result == -1)
150 0 : return G_TLS_INTERACTION_FAILED;
151 0 : return result;
152 : }
153 :
154 : static void
155 0 : gkd_ssh_agent_interaction_set_property (GObject *object,
156 : guint prop_id,
157 : const GValue *value,
158 : GParamSpec *pspec)
159 : {
160 0 : GkdSshAgentInteraction *self = GKD_SSH_AGENT_INTERACTION (object);
161 :
162 0 : switch (prop_id) {
163 0 : case PROP_PROMPTER_NAME:
164 0 : self->prompter_name = g_value_dup_string (value);
165 0 : break;
166 0 : default:
167 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
168 0 : break;
169 : }
170 0 : }
171 :
172 : static void
173 0 : gkd_ssh_agent_interaction_finalize (GObject *object)
174 : {
175 0 : GkdSshAgentInteraction *self = GKD_SSH_AGENT_INTERACTION (object);
176 :
177 0 : g_free (self->prompter_name);
178 :
179 0 : G_OBJECT_CLASS (gkd_ssh_agent_interaction_parent_class)->finalize (object);
180 0 : }
181 :
182 : static void
183 0 : gkd_ssh_agent_interaction_class_init (GkdSshAgentInteractionClass *klass)
184 : {
185 0 : GTlsInteractionClass *interaction_class = G_TLS_INTERACTION_CLASS (klass);
186 0 : GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
187 :
188 0 : interaction_class->ask_password_async = gkd_ssh_agent_interaction_ask_password_async;
189 0 : interaction_class->ask_password_finish = gkd_ssh_agent_interaction_ask_password_finish;
190 :
191 0 : gobject_class->set_property = gkd_ssh_agent_interaction_set_property;
192 0 : gobject_class->finalize = gkd_ssh_agent_interaction_finalize;
193 :
194 0 : g_object_class_install_property (gobject_class, PROP_PROMPTER_NAME,
195 : g_param_spec_string ("prompter-name", "Prompter-name", "Prompter-name",
196 : NULL,
197 : G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE));
198 0 : }
199 :
200 : GTlsInteraction *
201 0 : gkd_ssh_agent_interaction_new (const gchar *prompter_name)
202 : {
203 0 : return g_object_new (GKD_TYPE_SSH_AGENT_INTERACTION, "prompter-name", prompter_name, NULL);
204 : }
|