Branch data Line data Source code
1 : : /*
2 : : * gnome-keyring
3 : : *
4 : : * Copyright (C) 2011 Collabora Ltd.
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 <http://www.gnu.org/licenses/>.
18 : : *
19 : : * Author: Stef Walter <stefw@collabora.co.uk>
20 : : */
21 : :
22 : : #include "config.h"
23 : :
24 : : #include "gcr-gnupg-importer.h"
25 : : #include "gcr-gnupg-process.h"
26 : : #include "gcr-internal.h"
27 : :
28 : : #include <glib/gi18n-lib.h>
29 : :
30 : : enum {
31 : : PROP_0,
32 : : PROP_LABEL,
33 : : PROP_IMPORTED,
34 : : PROP_DIRECTORY,
35 : : PROP_INTERACTION,
36 : : PROP_URI
37 : : };
38 : :
39 : : struct _GcrGnupgImporterPrivate {
40 : : GcrGnupgProcess *process;
41 : : GMemoryInputStream *packets;
42 : : GTlsInteraction *interaction;
43 : : gchar *first_error;
44 : : GArray *imported;
45 : : };
46 : :
47 : : static void gcr_gnupg_importer_iface (GcrImporterInterface *iface);
48 : :
49 [ # # # # : 0 : G_DEFINE_TYPE_WITH_CODE (GcrGnupgImporter, _gcr_gnupg_importer, G_TYPE_OBJECT,
# # ]
50 : : G_ADD_PRIVATE (GcrGnupgImporter);
51 : : G_IMPLEMENT_INTERFACE (GCR_TYPE_IMPORTER, gcr_gnupg_importer_iface);
52 : : );
53 : :
54 : : static void
55 : 0 : _gcr_gnupg_importer_init (GcrGnupgImporter *self)
56 : : {
57 : 0 : self->pv = _gcr_gnupg_importer_get_instance_private (self);
58 : 0 : self->pv->packets = G_MEMORY_INPUT_STREAM (g_memory_input_stream_new ());
59 : 0 : self->pv->imported = g_array_new (TRUE, TRUE, sizeof (gchar *));
60 : 0 : }
61 : :
62 : : static void
63 : 0 : _gcr_gnupg_importer_dispose (GObject *obj)
64 : : {
65 : 0 : GcrGnupgImporter *self = GCR_GNUPG_IMPORTER (obj);
66 : :
67 [ # # ]: 0 : if (self->pv->process)
68 : 0 : g_object_run_dispose (G_OBJECT (self->pv->process));
69 [ # # ]: 0 : g_clear_object (&self->pv->process);
70 [ # # ]: 0 : g_clear_object (&self->pv->packets);
71 [ # # ]: 0 : g_clear_object (&self->pv->interaction);
72 : :
73 : 0 : G_OBJECT_CLASS (_gcr_gnupg_importer_parent_class)->dispose (obj);
74 : 0 : }
75 : :
76 : : static void
77 : 0 : _gcr_gnupg_importer_finalize (GObject *obj)
78 : : {
79 : 0 : GcrGnupgImporter *self = GCR_GNUPG_IMPORTER (obj);
80 : :
81 : 0 : g_array_free (self->pv->imported, TRUE);
82 : 0 : g_free (self->pv->first_error);
83 : :
84 : 0 : G_OBJECT_CLASS (_gcr_gnupg_importer_parent_class)->finalize (obj);
85 : 0 : }
86 : :
87 : : static gchar *
88 : 0 : calculate_label (GcrGnupgImporter *self)
89 : : {
90 : : const gchar *directory;
91 : :
92 : 0 : directory = _gcr_gnupg_process_get_directory (self->pv->process);
93 [ # # ]: 0 : if (directory == NULL)
94 : 0 : return g_strdup (_("GnuPG Keyring"));
95 : : else
96 : 0 : return g_strdup_printf (_("GnuPG Keyring: %s"), directory);
97 : : }
98 : :
99 : : static gchar *
100 : 0 : calculate_uri (GcrGnupgImporter *self)
101 : : {
102 : : const gchar *directory;
103 : :
104 : 0 : directory = _gcr_gnupg_process_get_directory (self->pv->process);
105 [ # # ]: 0 : if (directory == NULL)
106 : 0 : return g_strdup ("gnupg://");
107 : : else
108 : 0 : return g_strdup_printf ("gnupg://%s", directory);
109 : : }
110 : :
111 : : static gboolean
112 : 0 : on_process_error_line (GcrGnupgProcess *process,
113 : : const gchar *line,
114 : : gpointer user_data)
115 : : {
116 : 0 : GcrGnupgImporter *self = GCR_GNUPG_IMPORTER (user_data);
117 : :
118 [ # # ]: 0 : if (self->pv->first_error)
119 : 0 : return TRUE;
120 : :
121 [ # # ]: 0 : if (g_str_has_prefix (line, "gpg: ")) {
122 : 0 : line += 5;
123 [ # # ]: 0 : if (g_pattern_match_simple ("key ????????:*", line))
124 : 0 : line += 13;
125 : : }
126 : :
127 [ # # # # ]: 0 : while (line[0] && g_ascii_isspace (line[0]))
128 : 0 : line++;
129 : :
130 : 0 : self->pv->first_error = g_strdup (line);
131 : 0 : g_strstrip (self->pv->first_error);
132 : 0 : return TRUE;
133 : : }
134 : :
135 : : static gboolean
136 : 0 : on_process_status_record (GcrGnupgProcess *process,
137 : : GcrRecord *record,
138 : : gpointer user_data)
139 : : {
140 : 0 : GcrGnupgImporter *self = GCR_GNUPG_IMPORTER (user_data);
141 : : const gchar *value;
142 : : gchar *fingerprint;
143 : :
144 [ # # ]: 0 : if (_gcr_record_get_schema (record) != GCR_RECORD_SCHEMA_IMPORT_OK)
145 : 0 : return TRUE;
146 : :
147 : 0 : value = _gcr_record_get_raw (record, GCR_RECORD_IMPORT_FINGERPRINT);
148 [ # # # # ]: 0 : if (value != NULL && value[0] != 0) {
149 : 0 : fingerprint = g_strdup (value);
150 : 0 : g_array_append_val (self->pv->imported, fingerprint);
151 : : }
152 : :
153 : 0 : return TRUE;
154 : : }
155 : :
156 : : static void
157 : 0 : _gcr_gnupg_importer_set_property (GObject *obj,
158 : : guint prop_id,
159 : : const GValue *value,
160 : : GParamSpec *pspec)
161 : : {
162 : 0 : GcrGnupgImporter *self = GCR_GNUPG_IMPORTER (obj);
163 : :
164 [ # # # ]: 0 : switch (prop_id) {
165 : 0 : case PROP_DIRECTORY:
166 : 0 : self->pv->process = _gcr_gnupg_process_new (g_value_get_string (value), NULL);
167 : 0 : _gcr_gnupg_process_set_input_stream (self->pv->process, G_INPUT_STREAM (self->pv->packets));
168 : 0 : g_signal_connect (self->pv->process, "error-line", G_CALLBACK (on_process_error_line), self);
169 : 0 : g_signal_connect (self->pv->process, "status-record", G_CALLBACK (on_process_status_record), self);
170 : 0 : break;
171 : 0 : case PROP_INTERACTION:
172 [ # # ]: 0 : g_clear_object (&self->pv->interaction);
173 : 0 : self->pv->interaction = g_value_dup_object (value);
174 : 0 : break;
175 : 0 : default:
176 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
177 : 0 : break;
178 : : }
179 : 0 : }
180 : :
181 : : static void
182 : 0 : _gcr_gnupg_importer_get_property (GObject *obj,
183 : : guint prop_id,
184 : : GValue *value,
185 : : GParamSpec *pspec)
186 : : {
187 : 0 : GcrGnupgImporter *self = GCR_GNUPG_IMPORTER (obj);
188 : :
189 [ # # # # : 0 : switch (prop_id) {
# # ]
190 : 0 : case PROP_LABEL:
191 : 0 : g_value_take_string (value, calculate_label (self));
192 : 0 : break;
193 : 0 : case PROP_IMPORTED:
194 : 0 : g_value_set_boxed (value, _gcr_gnupg_importer_get_imported (self));
195 : 0 : break;
196 : 0 : case PROP_DIRECTORY:
197 : 0 : g_value_set_string (value, _gcr_gnupg_process_get_directory (self->pv->process));
198 : 0 : break;
199 : 0 : case PROP_INTERACTION:
200 : 0 : g_value_set_object (value, self->pv->interaction);
201 : 0 : break;
202 : 0 : case PROP_URI:
203 : 0 : g_value_take_string (value, calculate_uri (self));
204 : 0 : break;
205 : 0 : default:
206 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
207 : 0 : break;
208 : : }
209 : 0 : }
210 : :
211 : : static void
212 : 0 : _gcr_gnupg_importer_class_init (GcrGnupgImporterClass *klass)
213 : : {
214 : 0 : GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
215 : 0 : GckBuilder builder = GCK_BUILDER_INIT;
216 : :
217 : 0 : gobject_class->dispose = _gcr_gnupg_importer_dispose;
218 : 0 : gobject_class->finalize = _gcr_gnupg_importer_finalize;
219 : 0 : gobject_class->set_property = _gcr_gnupg_importer_set_property;
220 : 0 : gobject_class->get_property = _gcr_gnupg_importer_get_property;
221 : :
222 : 0 : g_object_class_override_property (gobject_class, PROP_LABEL, "label");
223 : 0 : g_object_class_override_property (gobject_class, PROP_INTERACTION, "interaction");
224 : 0 : g_object_class_override_property (gobject_class, PROP_URI, "uri");
225 : :
226 : 0 : g_object_class_install_property (gobject_class, PROP_IMPORTED,
227 : : g_param_spec_boxed ("imported", "Imported", "Fingerprints of imported keys",
228 : : G_TYPE_STRV,
229 : : G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
230 : :
231 : 0 : g_object_class_install_property (gobject_class, PROP_DIRECTORY,
232 : : g_param_spec_string ("directory", "Directory", "Directory to import keys to",
233 : : NULL,
234 : : G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
235 : :
236 : 0 : gck_builder_add_ulong (&builder, CKA_CLASS, CKO_GCR_GNUPG_RECORDS);
237 : 0 : gcr_importer_register (GCR_TYPE_GNUPG_IMPORTER, gck_builder_end (&builder));
238 : :
239 : 0 : _gcr_initialize_library ();
240 : 0 : }
241 : :
242 : : static GList *
243 : 0 : _gcr_gnupg_importer_create_for_parsed (GcrParsed *parsed)
244 : : {
245 : : GcrImporter *self;
246 : :
247 [ # # ]: 0 : if (gcr_parsed_get_format (parsed) != GCR_FORMAT_OPENPGP_PACKET)
248 : 0 : return NULL;
249 : :
250 : 0 : self = _gcr_gnupg_importer_new (NULL);
251 [ # # ]: 0 : if (!gcr_importer_queue_for_parsed (self, parsed))
252 : 0 : g_assert_not_reached ();
253 : :
254 : 0 : return g_list_append (NULL, self);
255 : : }
256 : :
257 : : static gboolean
258 : 0 : _gcr_gnupg_importer_queue_for_parsed (GcrImporter *importer,
259 : : GcrParsed *parsed)
260 : : {
261 : 0 : GcrGnupgImporter *self = GCR_GNUPG_IMPORTER (importer);
262 : : gconstpointer block;
263 : : gsize n_block;
264 : :
265 [ # # ]: 0 : if (gcr_parsed_get_format (parsed) != GCR_FORMAT_OPENPGP_PACKET)
266 : 0 : return FALSE;
267 : :
268 : 0 : block = gcr_parsed_get_data (parsed, &n_block);
269 [ # # ]: 0 : g_return_val_if_fail (block, FALSE);
270 : :
271 : 0 : g_memory_input_stream_add_data (self->pv->packets, g_memdup2 (block, n_block),
272 : : n_block, g_free);
273 : 0 : return TRUE;
274 : : }
275 : :
276 : : static void
277 : 0 : on_process_run_complete (GObject *source,
278 : : GAsyncResult *result,
279 : : gpointer user_data)
280 : : {
281 : 0 : GTask *task = G_TASK (user_data);
282 : 0 : GcrGnupgImporter *self = GCR_GNUPG_IMPORTER (g_task_get_source_object (task));
283 : 0 : GError *error = NULL;
284 : :
285 [ # # ]: 0 : if (!_gcr_gnupg_process_run_finish (GCR_GNUPG_PROCESS (source), result, &error)) {
286 [ # # # # ]: 0 : if (g_error_matches (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED) && self->pv->first_error) {
287 : 0 : g_task_return_new_error (task, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
288 : 0 : "%s", self->pv->first_error);
289 : 0 : g_error_free (error);
290 : : } else {
291 : 0 : g_task_return_error (task, g_steal_pointer (&error));
292 : : }
293 : : } else {
294 : 0 : g_task_return_boolean (task, TRUE);
295 : : }
296 : :
297 [ # # ]: 0 : g_clear_object (&task);
298 : 0 : }
299 : :
300 : : static void
301 : 0 : _gcr_gnupg_importer_import_async (GcrImporter *importer,
302 : : GCancellable *cancellable,
303 : : GAsyncReadyCallback callback,
304 : : gpointer user_data)
305 : : {
306 : 0 : GcrGnupgImporter *self = GCR_GNUPG_IMPORTER (importer);
307 : : GTask *task;
308 : 0 : const gchar *argv[] = { "--import", NULL };
309 : :
310 [ # # ]: 0 : g_clear_pointer (&self->pv->first_error, g_free);
311 : :
312 : 0 : task = g_task_new (importer, cancellable, callback, user_data);
313 [ # # ]: 0 : g_task_set_source_tag (task, _gcr_gnupg_importer_import_async);
314 : :
315 : 0 : _gcr_gnupg_process_run_async (self->pv->process, argv, NULL,
316 : : GCR_GNUPG_PROCESS_WITH_STATUS,
317 : : cancellable, on_process_run_complete,
318 : : g_steal_pointer (&task));
319 : :
320 [ # # ]: 0 : g_clear_object (&task);
321 : 0 : }
322 : :
323 : : static gboolean
324 : 0 : _gcr_gnupg_importer_import_finish (GcrImporter *importer,
325 : : GAsyncResult *result,
326 : : GError **error)
327 : : {
328 [ # # ]: 0 : g_return_val_if_fail (g_task_is_valid (result, importer), FALSE);
329 : :
330 : 0 : return g_task_propagate_boolean (G_TASK (result), error);
331 : : }
332 : :
333 : : static void
334 : 0 : gcr_gnupg_importer_iface (GcrImporterInterface *iface)
335 : : {
336 : 0 : iface->create_for_parsed = _gcr_gnupg_importer_create_for_parsed;
337 : 0 : iface->queue_for_parsed = _gcr_gnupg_importer_queue_for_parsed;
338 : 0 : iface->import_async = _gcr_gnupg_importer_import_async;
339 : 0 : iface->import_finish = _gcr_gnupg_importer_import_finish;
340 : 0 : }
341 : :
342 : : /**
343 : : * _gcr_gnupg_importer_new:
344 : : * @directory: (nullable): the directory to import to, or %NULL for default
345 : : *
346 : : * Create a new #GcrGnupgImporter.
347 : : *
348 : : * Returns: (transfer full) (type Gcr.GnupgImporter): the new importer
349 : : */
350 : : GcrImporter *
351 : 0 : _gcr_gnupg_importer_new (const gchar *directory)
352 : : {
353 : 0 : return g_object_new (GCR_TYPE_GNUPG_IMPORTER,
354 : : "directory", directory,
355 : : NULL);
356 : : }
357 : :
358 : : const gchar **
359 : 0 : _gcr_gnupg_importer_get_imported (GcrGnupgImporter *self)
360 : : {
361 [ # # # # : 0 : g_return_val_if_fail (GCR_IS_GNUPG_IMPORTER (self), NULL);
# # # # ]
362 : 0 : return (const gchar **)self->pv->imported->data;
363 : : }
|