File: | modules/printbackends/cups/ctkcupssecretsutils.c |
Warning: | line 77, column 41 Casting a non-structure type to a structure type and accessing a field can lead to memory access errors or data corruption |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* ctkcupssecretsutils.h: Helper to use a secrets service for printer passwords |
2 | * Copyright (C) 2014, Intevation GmbH |
3 | * |
4 | * This library is free software; you can redistribute it and/or |
5 | * modify it under the terms of the GNU Lesser General Public |
6 | * License as published by the Free Software Foundation; either |
7 | * version 2 of the License, or (at your option) any later version. |
8 | * |
9 | * This library is distributed in the hope that it will be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | * Lesser General Public License for more details. |
13 | * |
14 | * You should have received a copy of the GNU Lesser General Public |
15 | * License along with this library. If not, see <http://www.gnu.org/licenses/>. |
16 | */ |
17 | |
18 | #include <glib.h> |
19 | #include <gio/gio.h> |
20 | #include <string.h> |
21 | |
22 | #include <ctk/ctk.h> |
23 | |
24 | #include "ctkcupssecretsutils.h" |
25 | |
26 | #define SECRETS_BUS"org.freedesktop.secrets" "org.freedesktop.secrets" |
27 | #define SECRETS_IFACE(interface)"org.freedesktop.Secret."interface "org.freedesktop.Secret."interface |
28 | #define SECRETS_PATH"/org/freedesktop/secrets" "/org/freedesktop/secrets" |
29 | #define SECRETS_TIMEOUT5000 5000 |
30 | |
31 | typedef enum |
32 | { |
33 | SECRETS_SERVICE_ACTION_QUERY, |
34 | SECRETS_SERVICE_ACTION_STORE |
35 | } SecretsServiceAction; |
36 | |
37 | typedef struct |
38 | { |
39 | GDBusConnection *dbus_connection; |
40 | SecretsServiceAction action; |
41 | gchar **auth_info, |
42 | **auth_info_labels, |
43 | **auth_info_required, |
44 | *printer_uri, |
45 | *session_path, |
46 | *collection_path; |
47 | GDBusProxy *item_proxy; |
48 | guint prompt_subscription; |
49 | } SecretsServiceData; |
50 | |
51 | /** |
52 | * create_attributes: |
53 | * @printer_uri: URI for the printer |
54 | * @additional_labels: Optional labels for additional attributes |
55 | * @additional_attrs: Optional additional attributes |
56 | * |
57 | * Creates a GVariant dictionary with key / value pairs that |
58 | * can be used to identify a secret item. |
59 | * |
60 | * Returns: A GVariant dictionary of string pairs or NULL on error. |
61 | */ |
62 | static GVariant * |
63 | create_attributes (const gchar *printer_uri, |
64 | gchar **additional_attrs, |
65 | gchar **additional_labels) |
66 | { |
67 | GVariantBuilder *attr_builder = NULL((void*)0); |
68 | GVariant *ret = NULL((void*)0); |
69 | |
70 | if (printer_uri == NULL((void*)0)) |
71 | { |
72 | CTK_NOTE (PRINTING,do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) { g_print ("create_attributes called with invalid parameters.\n" ); }; } while (0) |
73 | g_print ("create_attributes called with invalid parameters.\n"))do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) { g_print ("create_attributes called with invalid parameters.\n" ); }; } while (0); |
74 | return NULL((void*)0); |
75 | } |
76 | |
77 | attr_builder = g_variant_builder_new (G_VARIANT_TYPE_DICTIONARY((const GVariantType *) "a{?*}")); |
Casting a non-structure type to a structure type and accessing a field can lead to memory access errors or data corruption | |
78 | /* The printer uri is the main identifying part */ |
79 | g_variant_builder_add (attr_builder, "{ss}", "uri", printer_uri); |
80 | |
81 | if (additional_labels != NULL((void*)0)) |
82 | { |
83 | int i; |
84 | for (i = 0; additional_labels[i] != NULL((void*)0); i++) |
85 | { |
86 | g_variant_builder_add (attr_builder, "{ss}", |
87 | additional_labels[i], |
88 | additional_attrs[i]); |
89 | } |
90 | } |
91 | |
92 | ret = g_variant_builder_end (attr_builder); |
93 | g_variant_builder_unref (attr_builder); |
94 | |
95 | return ret; |
96 | } |
97 | |
98 | static void |
99 | get_secret_cb (GObject *source_object, |
100 | GAsyncResult *res, |
101 | gpointer user_data) |
102 | { |
103 | GTask *task; |
104 | SecretsServiceData *task_data; |
105 | GError *error = NULL((void*)0); |
106 | GVariant *output, |
107 | *attributes; |
108 | gchar **auth_info = NULL((void*)0), |
109 | *key = NULL((void*)0), |
110 | *value = NULL((void*)0); |
111 | GVariantIter *iter = NULL((void*)0); |
112 | guint i, required_len; |
113 | gint pw_field = -1; |
114 | |
115 | task = user_data; |
116 | task_data = g_task_get_task_data (task); |
117 | |
118 | output = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object)((((GDBusProxy*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((source_object)), ((g_dbus_proxy_get_type ())))))), |
119 | res, |
120 | &error); |
121 | if (output == NULL((void*)0)) |
122 | { |
123 | g_task_return_error (task, error); |
124 | return; |
125 | } |
126 | |
127 | attributes = g_dbus_proxy_get_cached_property (task_data->item_proxy, |
128 | "Attributes"); |
129 | if (attributes == NULL((void*)0)) |
130 | { |
131 | CTK_NOTE (PRINTING, g_print ("Failed to lookup attributes.\n"))do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) { g_print ("Failed to lookup attributes.\n"); }; } while (0); |
132 | g_variant_unref (output); |
133 | g_task_return_pointer (task, NULL((void*)0), NULL((void*)0)); |
134 | return; |
135 | } |
136 | |
137 | /* Iterate over the attributes to fill the auth info */ |
138 | g_variant_get (attributes, "a{ss}", &iter); |
139 | |
140 | auth_info = g_new0 (gchar *,((gchar * *) g_malloc0_n ((g_strv_length (task_data->auth_info_required ) + 1), sizeof (gchar *))) |
141 | g_strv_length (task_data->auth_info_required) + 1)((gchar * *) g_malloc0_n ((g_strv_length (task_data->auth_info_required ) + 1), sizeof (gchar *))); |
142 | |
143 | while (g_variant_iter_loop (iter, "{ss}", &key, &value)) |
144 | { |
145 | /* Match attributes with required auth info */ |
146 | for (i = 0; task_data->auth_info_required[i] != NULL((void*)0); i++) |
147 | { |
148 | if ((strcmp (key, "user") == 0 || |
149 | strcmp (key, "username") == 0) && |
150 | strcmp (task_data->auth_info_required[i], |
151 | "username") == 0) |
152 | { |
153 | auth_info[i] = g_strdup (value)g_strdup_inline (value); |
154 | } |
155 | else if (strcmp (key, "domain") == 0 && |
156 | strcmp (task_data->auth_info_required[i], "domain") == 0) |
157 | { |
158 | auth_info[i] = g_strdup (value)g_strdup_inline (value); |
159 | } |
160 | else if ((strcmp (key, "hostname") == 0 || |
161 | strcmp (key, "server") == 0 ) && |
162 | strcmp (task_data->auth_info_required[i], "hostname") == 0) |
163 | { |
164 | auth_info[i] = g_strdup (value)g_strdup_inline (value); |
165 | } |
166 | else if (strcmp (task_data->auth_info_required[i], "password") == 0) |
167 | { |
168 | pw_field = i; |
169 | } |
170 | } |
171 | } |
172 | |
173 | if (pw_field == -1) |
174 | { |
175 | /* should not happen... */ |
176 | CTK_NOTE (PRINTING, g_print ("No password required?.\n"))do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) { g_print ("No password required?.\n"); }; } while (0); |
177 | g_variant_unref (output); |
178 | goto fail; |
179 | } |
180 | else |
181 | { |
182 | GVariant *secret, |
183 | *s_value; |
184 | gconstpointer ba_passwd = NULL((void*)0); |
185 | gsize len = 0; |
186 | |
187 | secret = g_variant_get_child_value (output, 0); |
188 | g_variant_unref (output); |
189 | if (secret == NULL((void*)0) || g_variant_n_children (secret) != 4) |
190 | { |
191 | CTK_NOTE (PRINTING, g_print ("Get secret response invalid.\n"))do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) { g_print ("Get secret response invalid.\n"); }; } while (0); |
192 | if (secret != NULL((void*)0)) |
193 | g_variant_unref (secret); |
194 | goto fail; |
195 | } |
196 | s_value = g_variant_get_child_value (secret, 2); |
197 | ba_passwd = g_variant_get_fixed_array (s_value, |
198 | &len, |
199 | sizeof (guchar)); |
200 | |
201 | g_variant_unref (secret); |
202 | |
203 | if (ba_passwd == NULL((void*)0)) |
204 | { |
205 | CTK_NOTE (PRINTING, g_print ("Invalid / no secret found.\n"))do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) { g_print ("Invalid / no secret found.\n"); }; } while (0); |
206 | g_variant_unref (s_value); |
207 | goto fail; |
208 | } |
209 | |
210 | auth_info[pw_field] = g_strndup (ba_passwd, len); |
211 | g_variant_unref (s_value); |
212 | } |
213 | |
214 | for (i = 0; task_data->auth_info_required[i] != NULL((void*)0); i++) |
215 | { |
216 | if (auth_info[i] == NULL((void*)0)) |
217 | { |
218 | /* Error out if we did not find everything */ |
219 | CTK_NOTE (PRINTING, g_print ("Failed to lookup required attribute: %s.\n",do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) { g_print ("Failed to lookup required attribute: %s.\n", task_data ->auth_info_required[i]); }; } while (0) |
220 | task_data->auth_info_required[i]))do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) { g_print ("Failed to lookup required attribute: %s.\n", task_data ->auth_info_required[i]); }; } while (0); |
221 | goto fail; |
222 | } |
223 | } |
224 | |
225 | g_task_return_pointer (task, auth_info, NULL((void*)0)); |
226 | return; |
227 | |
228 | fail: |
229 | /* Error out */ |
230 | CTK_NOTE (PRINTING, g_print ("Failed to lookup secret.\n"))do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) { g_print ("Failed to lookup secret.\n"); }; } while (0); |
231 | required_len = g_strv_length (task_data->auth_info_required); |
232 | for (i = 0; i < required_len; i++) |
233 | { |
234 | /* Not all fields of auth_info are neccessarily written so we can not |
235 | use strfreev here */ |
236 | g_free (auth_info[i]); |
237 | } |
238 | g_free (auth_info); |
239 | g_task_return_pointer (task, NULL((void*)0), NULL((void*)0)); |
240 | } |
241 | |
242 | static void |
243 | create_item_cb (GObject *source_object, |
244 | GAsyncResult *res, |
245 | gpointer user_data) |
246 | { |
247 | GTask *task; |
248 | GError *error = NULL((void*)0); |
249 | GVariant *output; |
250 | gchar *item = NULL((void*)0); |
251 | |
252 | task = user_data; |
253 | |
254 | output = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object)((((GDBusConnection*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((source_object)), ((g_dbus_connection_get_type ())))))), |
255 | res, |
256 | &error); |
257 | if (output == NULL((void*)0)) |
258 | { |
259 | g_task_return_error (task, error); |
260 | return; |
261 | } |
262 | |
263 | g_variant_get (output, "(&o&o)", &item, NULL((void*)0)); |
264 | if (item != NULL((void*)0) && strlen (item) > 1) |
265 | { |
266 | CTK_NOTE (PRINTING, g_print ("Successfully stored auth info.\n"))do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) { g_print ("Successfully stored auth info.\n"); }; } while (0); |
267 | g_task_return_pointer (task, NULL((void*)0), NULL((void*)0)); |
268 | return; |
269 | } |
270 | g_variant_unref (output); |
271 | } |
272 | |
273 | static void |
274 | do_store_auth_info (GTask *task) |
275 | { |
276 | GVariant *attributes = NULL((void*)0), |
277 | *properties = NULL((void*)0), |
278 | *secret = NULL((void*)0); |
279 | gchar **additional_attrs = NULL((void*)0), |
280 | **additional_labels = NULL((void*)0), |
281 | *password = NULL((void*)0); |
282 | SecretsServiceData *task_data = g_task_get_task_data (task); |
283 | guint i, |
284 | length, |
285 | additional_count = 0; |
286 | GVariantBuilder *prop_builder = NULL((void*)0); |
287 | |
288 | length = g_strv_length (task_data->auth_info_labels); |
289 | |
290 | additional_attrs = g_new0 (gchar *, length + 1)((gchar * *) g_malloc0_n ((length + 1), sizeof (gchar *))); |
291 | additional_labels = g_new0 (gchar *, length + 1)((gchar * *) g_malloc0_n ((length + 1), sizeof (gchar *))); |
292 | /* The labels user and server are chosen to be compatible with |
293 | the attributes used by system-config-printer */ |
294 | for (i = 0; task_data->auth_info_labels[i] != NULL((void*)0); i++) |
295 | { |
296 | if (g_strcmp0 (task_data->auth_info_labels[i], "username") == 0) |
297 | { |
298 | additional_attrs[additional_count] = task_data->auth_info[i]; |
299 | additional_labels[additional_count++] = "user"; |
300 | } |
301 | else if (g_strcmp0 (task_data->auth_info_labels[i], "hostname") == 0) |
302 | { |
303 | additional_attrs[additional_count] = task_data->auth_info[i]; |
304 | additional_labels[additional_count++] = "server"; |
305 | } |
306 | else if (g_strcmp0 (task_data->auth_info_labels[i], "password") == 0) |
307 | { |
308 | password = task_data->auth_info[i]; |
309 | } |
310 | } |
311 | |
312 | attributes = create_attributes (task_data->printer_uri, |
313 | additional_attrs, |
314 | additional_labels); |
315 | g_free (additional_labels); |
316 | g_free (additional_attrs); |
317 | if (attributes == NULL((void*)0)) |
318 | { |
319 | CTK_NOTE (PRINTING, g_print ("Failed to create attributes.\n"))do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) { g_print ("Failed to create attributes.\n"); }; } while (0); |
320 | g_task_return_pointer (task, NULL((void*)0), NULL((void*)0)); |
321 | return; |
322 | } |
323 | |
324 | if (password == NULL((void*)0)) |
325 | { |
326 | CTK_NOTE (PRINTING, g_print ("No secret to store.\n"))do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) { g_print ("No secret to store.\n"); }; } while (0); |
327 | g_task_return_pointer (task, NULL((void*)0), NULL((void*)0)); |
328 | return; |
329 | } |
330 | |
331 | prop_builder = g_variant_builder_new (G_VARIANT_TYPE_DICTIONARY((const GVariantType *) "a{?*}")); |
332 | |
333 | g_variant_builder_add (prop_builder, "{sv}", SECRETS_IFACE ("Item.Label")"org.freedesktop.Secret.""Item.Label", |
334 | g_variant_new_string (task_data->printer_uri)); |
335 | g_variant_builder_add (prop_builder, "{sv}", SECRETS_IFACE ("Item.Attributes")"org.freedesktop.Secret.""Item.Attributes", |
336 | attributes); |
337 | |
338 | properties = g_variant_builder_end (prop_builder); |
339 | |
340 | g_variant_builder_unref (prop_builder); |
341 | |
342 | secret = g_variant_new ("(oay@ays)", |
343 | task_data->session_path, |
344 | NULL((void*)0), |
345 | g_variant_new_bytestring (password), |
346 | "text/plain"); |
347 | |
348 | g_dbus_connection_call (task_data->dbus_connection, |
349 | SECRETS_BUS"org.freedesktop.secrets", |
350 | task_data->collection_path, |
351 | SECRETS_IFACE ("Collection")"org.freedesktop.Secret.""Collection", |
352 | "CreateItem", |
353 | g_variant_new ("(@a{sv}@(oayays)b)", |
354 | properties, |
355 | secret, |
356 | TRUE(!(0))), |
357 | G_VARIANT_TYPE ("(oo)")(g_variant_type_checked_ (("(oo)"))), |
358 | G_DBUS_CALL_FLAGS_NONE, |
359 | SECRETS_TIMEOUT5000, |
360 | g_task_get_cancellable (task), |
361 | create_item_cb, |
362 | task); |
363 | } |
364 | |
365 | static void |
366 | prompt_completed_cb (GDBusConnection *connection G_GNUC_UNUSED__attribute__ ((__unused__)), |
367 | const gchar *sender_name G_GNUC_UNUSED__attribute__ ((__unused__)), |
368 | const gchar *object_path G_GNUC_UNUSED__attribute__ ((__unused__)), |
369 | const gchar *interface_name G_GNUC_UNUSED__attribute__ ((__unused__)), |
370 | const gchar *signal_name G_GNUC_UNUSED__attribute__ ((__unused__)), |
371 | GVariant *parameters, |
372 | gpointer user_data) |
373 | { |
374 | GTask *task; |
375 | SecretsServiceData *task_data; |
376 | GVariant *dismissed; |
377 | gboolean is_dismissed = TRUE(!(0)); |
378 | |
379 | task = user_data; |
380 | task_data = g_task_get_task_data (task); |
381 | |
382 | g_dbus_connection_signal_unsubscribe (task_data->dbus_connection, |
383 | task_data->prompt_subscription); |
384 | task_data->prompt_subscription = 0; |
385 | |
386 | dismissed = g_variant_get_child_value (parameters, 0); |
387 | |
388 | if (dismissed == NULL((void*)0)) |
389 | { |
390 | CTK_NOTE (PRINTING, g_print ("Invalid prompt signal.\n"))do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) { g_print ("Invalid prompt signal.\n"); }; } while (0); |
391 | g_task_return_pointer (task, NULL((void*)0), NULL((void*)0)); |
392 | return; |
393 | } |
394 | |
395 | g_variant_get (dismissed, "b", &is_dismissed); |
396 | g_variant_unref (dismissed); |
397 | |
398 | if (is_dismissed) |
399 | { |
400 | CTK_NOTE (PRINTING, g_print ("Collection unlock dismissed.\n"))do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) { g_print ("Collection unlock dismissed.\n"); }; } while (0); |
401 | g_task_return_pointer (task, NULL((void*)0), NULL((void*)0)); |
402 | return; |
403 | } |
404 | |
405 | /* Prompt successfull, proceed to get or store secret */ |
406 | switch (task_data->action) |
407 | { |
408 | case SECRETS_SERVICE_ACTION_STORE: |
409 | do_store_auth_info (task); |
410 | break; |
411 | |
412 | case SECRETS_SERVICE_ACTION_QUERY: |
413 | g_dbus_proxy_call (task_data->item_proxy, |
414 | "GetSecret", |
415 | g_variant_new ("(o)", |
416 | task_data->session_path), |
417 | G_DBUS_CALL_FLAGS_NONE, |
418 | SECRETS_TIMEOUT5000, |
419 | g_task_get_cancellable (task), |
420 | get_secret_cb, |
421 | task); |
422 | break; |
423 | } |
424 | } |
425 | |
426 | static void |
427 | prompt_cb (GObject *source_object, |
428 | GAsyncResult *res, |
429 | gpointer user_data) |
430 | { |
431 | GTask *task; |
432 | SecretsServiceData *task_data; |
433 | GError *error = NULL((void*)0); |
434 | GVariant *output; |
435 | |
436 | task = user_data; |
437 | task_data = g_task_get_task_data (task); |
438 | |
439 | output = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object)((((GDBusConnection*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((source_object)), ((g_dbus_connection_get_type ())))))), |
440 | res, |
441 | &error); |
442 | if (output == NULL((void*)0)) |
443 | { |
444 | g_task_return_error (task, error); |
445 | return; |
446 | } |
447 | |
448 | g_variant_unref (output); |
449 | |
450 | /* Connect to the prompt's completed signal */ |
451 | task_data->prompt_subscription = |
452 | g_dbus_connection_signal_subscribe (task_data->dbus_connection, |
453 | NULL((void*)0), |
454 | SECRETS_IFACE ("Prompt")"org.freedesktop.Secret.""Prompt", |
455 | "Completed", |
456 | NULL((void*)0), |
457 | NULL((void*)0), |
458 | G_DBUS_SIGNAL_FLAGS_NONE, |
459 | prompt_completed_cb, |
460 | task, |
461 | NULL((void*)0)); |
462 | } |
463 | |
464 | static void |
465 | unlock_collection_cb (GObject *source_object, |
466 | GAsyncResult *res, |
467 | gpointer user_data) |
468 | { |
469 | GTask *task; |
470 | SecretsServiceData *task_data; |
471 | GError *error = NULL((void*)0); |
472 | GVariant *output; |
473 | const gchar *prompt_path; |
474 | |
475 | task = user_data; |
476 | task_data = g_task_get_task_data (task); |
477 | |
478 | output = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object)((((GDBusConnection*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((source_object)), ((g_dbus_connection_get_type ())))))), |
479 | res, |
480 | &error); |
481 | if (output == NULL((void*)0)) |
482 | { |
483 | g_task_return_error (task, error); |
484 | return; |
485 | } |
486 | |
487 | g_variant_get (output, "(@ao&o)", NULL((void*)0), &prompt_path); |
488 | |
489 | if (prompt_path != NULL((void*)0) && strlen (prompt_path) > 1) |
490 | { |
491 | g_dbus_connection_call (task_data->dbus_connection, |
492 | SECRETS_BUS"org.freedesktop.secrets", |
493 | prompt_path, |
494 | SECRETS_IFACE ("Prompt")"org.freedesktop.Secret.""Prompt", |
495 | "Prompt", |
496 | g_variant_new ("(s)", "0"), |
497 | G_VARIANT_TYPE ("()")(g_variant_type_checked_ (("()"))), |
498 | G_DBUS_CALL_FLAGS_NONE, |
499 | SECRETS_TIMEOUT5000, |
500 | g_task_get_cancellable (task), |
501 | prompt_cb, |
502 | task); |
503 | } |
504 | else |
505 | { |
506 | switch (task_data->action) |
507 | { |
508 | case SECRETS_SERVICE_ACTION_STORE: |
509 | do_store_auth_info (task); |
510 | break; |
511 | |
512 | case SECRETS_SERVICE_ACTION_QUERY: |
513 | /* Prompt successfull proceed to get secret */ |
514 | g_dbus_proxy_call (task_data->item_proxy, |
515 | "GetSecret", |
516 | g_variant_new ("(o)", |
517 | task_data->session_path), |
518 | G_DBUS_CALL_FLAGS_NONE, |
519 | SECRETS_TIMEOUT5000, |
520 | g_task_get_cancellable (task), |
521 | get_secret_cb, |
522 | task); |
523 | break; |
524 | } |
525 | } |
526 | g_variant_unref (output); |
527 | } |
528 | |
529 | static void |
530 | unlock_read_alias_cb (GObject *source_object, |
531 | GAsyncResult *res, |
532 | gpointer user_data) |
533 | { |
534 | GTask *task; |
535 | SecretsServiceData *task_data; |
536 | GError *error = NULL((void*)0); |
537 | GVariant *output, *subresult; |
538 | gsize path_len = 0; |
539 | const gchar *collection_path; |
540 | const gchar *to_unlock[2]; |
541 | |
542 | task = user_data; |
543 | task_data = g_task_get_task_data (task); |
544 | |
545 | output = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object)((((GDBusConnection*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((source_object)), ((g_dbus_connection_get_type ())))))), |
546 | res, |
547 | &error); |
548 | if (output == NULL((void*)0)) |
549 | { |
550 | g_task_return_error (task, error); |
551 | return; |
552 | } |
553 | |
554 | subresult = g_variant_get_child_value (output, 0); |
555 | g_variant_unref (output); |
556 | |
557 | if (subresult == NULL((void*)0)) |
558 | { |
559 | CTK_NOTE (PRINTING, g_print ("Invalid ReadAlias response.\n"))do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) { g_print ("Invalid ReadAlias response.\n"); }; } while (0); |
560 | g_task_return_pointer (task, NULL((void*)0), NULL((void*)0)); |
561 | return; |
562 | } |
563 | |
564 | collection_path = g_variant_get_string (subresult, &path_len); |
565 | to_unlock[0] = collection_path; |
566 | to_unlock[1] = NULL((void*)0); |
567 | |
568 | task_data->collection_path = g_strdup (collection_path)g_strdup_inline (collection_path); |
569 | |
570 | g_dbus_connection_call (task_data->dbus_connection, |
571 | SECRETS_BUS"org.freedesktop.secrets", |
572 | SECRETS_PATH"/org/freedesktop/secrets", |
573 | SECRETS_IFACE ("Service")"org.freedesktop.Secret.""Service", |
574 | "Unlock", |
575 | g_variant_new ("(^ao)", to_unlock), |
576 | G_VARIANT_TYPE ("(aoo)")(g_variant_type_checked_ (("(aoo)"))), |
577 | G_DBUS_CALL_FLAGS_NONE, |
578 | SECRETS_TIMEOUT5000, |
579 | g_task_get_cancellable (task), |
580 | unlock_collection_cb, |
581 | task); |
582 | |
583 | g_variant_unref (subresult); |
584 | } |
585 | |
586 | static void |
587 | item_proxy_cb (GObject *source_object G_GNUC_UNUSED__attribute__ ((__unused__)), |
588 | GAsyncResult *res, |
589 | gpointer user_data) |
590 | { |
591 | GTask *task; |
592 | SecretsServiceData *task_data; |
593 | GError *error = NULL((void*)0); |
594 | GDBusProxy *item_proxy; |
595 | GVariant *locked; |
596 | gboolean is_locked; |
597 | |
598 | task = user_data; |
599 | task_data = g_task_get_task_data (task); |
600 | |
601 | item_proxy = g_dbus_proxy_new_finish (res, |
602 | &error); |
603 | if (item_proxy == NULL((void*)0)) |
604 | { |
605 | g_task_return_error (task, error); |
606 | return; |
607 | } |
608 | |
609 | task_data->item_proxy = item_proxy; |
610 | |
611 | locked = g_dbus_proxy_get_cached_property (item_proxy, "Locked"); |
612 | |
613 | if (locked == NULL((void*)0)) |
614 | { |
615 | CTK_NOTE (PRINTING, g_print ("Failed to look up \"Locked\" property on item.\n"))do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) { g_print ("Failed to look up \"Locked\" property on item.\n") ; }; } while (0); |
616 | g_task_return_pointer (task, NULL((void*)0), NULL((void*)0)); |
617 | return; |
618 | } |
619 | |
620 | g_variant_get (locked, "b", &is_locked); |
621 | g_variant_unref (locked); |
622 | |
623 | if (is_locked) |
624 | { |
625 | /* Go down the unlock -> lookup path */ |
626 | g_dbus_connection_call (task_data->dbus_connection, |
627 | SECRETS_BUS"org.freedesktop.secrets", |
628 | SECRETS_PATH"/org/freedesktop/secrets", |
629 | SECRETS_IFACE ("Service")"org.freedesktop.Secret.""Service", |
630 | "ReadAlias", |
631 | g_variant_new ("(s)", "default"), |
632 | G_VARIANT_TYPE ("(o)")(g_variant_type_checked_ (("(o)"))), |
633 | G_DBUS_CALL_FLAGS_NONE, |
634 | SECRETS_TIMEOUT5000, |
635 | g_task_get_cancellable (task), |
636 | unlock_read_alias_cb, |
637 | task); |
638 | return; |
639 | } |
640 | |
641 | /* Unlocked proceed to get or store secret */ |
642 | switch (task_data->action) |
643 | { |
644 | case SECRETS_SERVICE_ACTION_STORE: |
645 | do_store_auth_info (task); |
646 | break; |
647 | |
648 | case SECRETS_SERVICE_ACTION_QUERY: |
649 | g_dbus_proxy_call (item_proxy, |
650 | "GetSecret", |
651 | g_variant_new ("(o)", |
652 | task_data->session_path), |
653 | G_DBUS_CALL_FLAGS_NONE, |
654 | SECRETS_TIMEOUT5000, |
655 | g_task_get_cancellable (task), |
656 | get_secret_cb, |
657 | task); |
658 | break; |
659 | } |
660 | } |
661 | |
662 | static void |
663 | search_items_cb (GObject *source_object, |
664 | GAsyncResult *res, |
665 | gpointer user_data) |
666 | { |
667 | GTask *task; |
668 | SecretsServiceData *task_data; |
669 | GError *error = NULL((void*)0); |
670 | GVariant *output; |
671 | gsize array_cnt, |
672 | i; |
673 | gboolean found_item = FALSE(0); |
674 | |
675 | task = user_data; |
676 | task_data = g_task_get_task_data (task); |
677 | |
678 | output = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object)((((GDBusConnection*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((source_object)), ((g_dbus_connection_get_type ())))))), |
679 | res, |
680 | &error); |
681 | if (output == NULL((void*)0)) |
682 | { |
683 | g_task_return_error (task, error); |
684 | return; |
685 | } |
686 | |
687 | array_cnt = g_variant_n_children (output); |
688 | |
689 | for (i = 0; i < array_cnt; i++) |
690 | { |
691 | GVariant * const item_paths = g_variant_get_child_value (output, i); |
692 | const gchar **items = NULL((void*)0); |
693 | |
694 | if (item_paths == NULL((void*)0)) |
695 | { |
696 | CTK_NOTE (PRINTING,do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) { g_print ("SearchItems returned invalid result.\n"); }; } while (0) |
697 | g_print ("SearchItems returned invalid result.\n"))do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) { g_print ("SearchItems returned invalid result.\n"); }; } while (0); |
698 | continue; |
699 | } |
700 | |
701 | items = g_variant_get_objv (item_paths, NULL((void*)0)); |
702 | |
703 | if (*items == NULL((void*)0)) |
704 | { |
705 | g_variant_unref (item_paths); |
706 | g_free ((gpointer) items); |
707 | continue; |
708 | } |
709 | |
710 | /* Access the first found item. */ |
711 | found_item = TRUE(!(0)); |
712 | g_dbus_proxy_new (task_data->dbus_connection, |
713 | G_DBUS_PROXY_FLAGS_NONE, |
714 | NULL((void*)0), |
715 | SECRETS_BUS"org.freedesktop.secrets", |
716 | *items, |
717 | SECRETS_IFACE ("Item")"org.freedesktop.Secret.""Item", |
718 | g_task_get_cancellable (task), |
719 | item_proxy_cb, |
720 | task); |
721 | g_free ((gpointer) items); |
722 | g_variant_unref (item_paths); |
723 | break; |
724 | } |
725 | g_variant_unref (output); |
726 | |
727 | if (!found_item) |
728 | { |
729 | CTK_NOTE (PRINTING, g_print ("No match found in secrets service.\n"))do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) { g_print ("No match found in secrets service.\n"); }; } while (0); |
730 | g_task_return_pointer (task, NULL((void*)0), NULL((void*)0)); |
731 | return; |
732 | } |
733 | } |
734 | |
735 | static void |
736 | open_session_cb (GObject *source_object, |
737 | GAsyncResult *res, |
738 | gpointer user_data) |
739 | { |
740 | GTask *task; |
741 | GVariant *output, |
742 | *session_variant; |
743 | SecretsServiceData *task_data; |
744 | GError *error = NULL((void*)0); |
745 | |
746 | task = user_data; |
747 | task_data = g_task_get_task_data (task); |
748 | |
749 | output = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object)((((GDBusConnection*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((source_object)), ((g_dbus_connection_get_type ())))))), |
750 | res, |
751 | &error); |
752 | if (output == NULL((void*)0)) |
753 | { |
754 | g_task_return_error (task, error); |
755 | return; |
756 | } |
757 | |
758 | session_variant = g_variant_get_child_value (output, 1); |
759 | |
760 | if (session_variant == NULL((void*)0)) |
761 | { |
762 | CTK_NOTE (PRINTING, g_print ("Invalid session path response.\n"))do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) { g_print ("Invalid session path response.\n"); }; } while (0); |
763 | g_variant_unref (output); |
764 | g_task_return_pointer (task, NULL((void*)0), NULL((void*)0)); |
765 | return; |
766 | } |
767 | |
768 | task_data->session_path = g_variant_dup_string (session_variant, NULL((void*)0)); |
769 | |
770 | if (task_data->session_path == NULL((void*)0)) |
771 | { |
772 | CTK_NOTE (PRINTING, g_print ("Invalid session path string value.\n"))do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) { g_print ("Invalid session path string value.\n"); }; } while (0); |
773 | g_variant_unref (session_variant); |
774 | g_variant_unref (output); |
775 | g_task_return_pointer (task, NULL((void*)0), NULL((void*)0)); |
776 | return; |
777 | } |
778 | |
779 | g_variant_unref (session_variant); |
780 | g_variant_unref (output); |
781 | |
782 | switch (task_data->action) |
783 | { |
784 | case SECRETS_SERVICE_ACTION_QUERY: |
785 | { |
786 | /* Search for the secret item */ |
787 | GVariant *secrets_attrs; |
788 | |
789 | secrets_attrs = create_attributes (task_data->printer_uri, NULL((void*)0), NULL((void*)0)); |
790 | if (secrets_attrs == NULL((void*)0)) |
791 | { |
792 | CTK_NOTE (PRINTING, g_print ("Failed to create attributes.\n"))do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) { g_print ("Failed to create attributes.\n"); }; } while (0); |
793 | g_task_return_pointer (task, NULL((void*)0), NULL((void*)0)); |
794 | return; |
795 | } |
796 | |
797 | g_dbus_connection_call (task_data->dbus_connection, |
798 | SECRETS_BUS"org.freedesktop.secrets", |
799 | SECRETS_PATH"/org/freedesktop/secrets", |
800 | SECRETS_IFACE ("Service")"org.freedesktop.Secret.""Service", |
801 | "SearchItems", |
802 | g_variant_new ("(@a{ss})", secrets_attrs), |
803 | G_VARIANT_TYPE ("(aoao)")(g_variant_type_checked_ (("(aoao)"))), |
804 | G_DBUS_CALL_FLAGS_NONE, |
805 | SECRETS_TIMEOUT5000, |
806 | g_task_get_cancellable (task), |
807 | search_items_cb, |
808 | task); |
809 | break; |
810 | } |
811 | |
812 | case SECRETS_SERVICE_ACTION_STORE: |
813 | { |
814 | /* Look up / unlock the default collection for storing */ |
815 | g_dbus_connection_call (task_data->dbus_connection, |
816 | SECRETS_BUS"org.freedesktop.secrets", |
817 | SECRETS_PATH"/org/freedesktop/secrets", |
818 | SECRETS_IFACE ("Service")"org.freedesktop.Secret.""Service", |
819 | "ReadAlias", |
820 | g_variant_new ("(s)", "default"), |
821 | G_VARIANT_TYPE ("(o)")(g_variant_type_checked_ (("(o)"))), |
822 | G_DBUS_CALL_FLAGS_NONE, |
823 | SECRETS_TIMEOUT5000, |
824 | g_task_get_cancellable (task), |
825 | unlock_read_alias_cb, |
826 | task); |
827 | break; |
828 | } |
829 | } |
830 | } |
831 | |
832 | static void |
833 | get_connection_cb (GObject *source_object G_GNUC_UNUSED__attribute__ ((__unused__)), |
834 | GAsyncResult *res, |
835 | gpointer user_data) |
836 | { |
837 | GTask *task; |
838 | SecretsServiceData *task_data; |
839 | GError *error = NULL((void*)0); |
840 | |
841 | task = user_data; |
842 | task_data = g_task_get_task_data (task); |
843 | |
844 | task_data->dbus_connection = g_bus_get_finish (res, &error); |
845 | if (task_data->dbus_connection == NULL((void*)0)) |
846 | { |
847 | g_task_return_error (task, error); |
848 | return; |
849 | } |
850 | |
851 | /* Now open a session */ |
852 | g_dbus_connection_call (task_data->dbus_connection, |
853 | SECRETS_BUS"org.freedesktop.secrets", |
854 | SECRETS_PATH"/org/freedesktop/secrets", |
855 | SECRETS_IFACE ("Service")"org.freedesktop.Secret.""Service", |
856 | "OpenSession", |
857 | g_variant_new ("(sv)", "plain", |
858 | g_variant_new_string ("")), |
859 | G_VARIANT_TYPE ("(vo)")(g_variant_type_checked_ (("(vo)"))), |
860 | G_DBUS_CALL_FLAGS_NONE, |
861 | SECRETS_TIMEOUT5000, |
862 | g_task_get_cancellable (task), |
863 | open_session_cb, |
864 | task); |
865 | } |
866 | |
867 | /** |
868 | * ctk_cups_secrets_service_watch: |
869 | * @appeared: The callback to call when the service interface appears |
870 | * @vanished: The callback to call when the service interface vanishes |
871 | * @user_data: A reference to the watching printbackend |
872 | * |
873 | * Registers a watch for the secrets service interface. |
874 | * |
875 | * Returns: The watcher id |
876 | */ |
877 | guint |
878 | ctk_cups_secrets_service_watch (GBusNameAppearedCallback appeared, |
879 | GBusNameVanishedCallback vanished, |
880 | gpointer user_data) |
881 | { |
882 | return g_bus_watch_name (G_BUS_TYPE_SESSION, |
883 | SECRETS_BUS"org.freedesktop.secrets", |
884 | G_BUS_NAME_WATCHER_FLAGS_AUTO_START, |
885 | appeared, |
886 | vanished, |
887 | user_data, |
888 | NULL((void*)0)); |
889 | } |
890 | |
891 | void |
892 | cleanup_task_data (gpointer data) |
893 | { |
894 | gint i; |
895 | SecretsServiceData *task_data = data; |
896 | |
897 | g_free (task_data->collection_path); |
898 | g_strfreev (task_data->auth_info_labels); |
899 | g_strfreev (task_data->auth_info_required); |
900 | g_free (task_data->printer_uri); |
901 | |
902 | if (task_data->auth_info != NULL((void*)0)) |
903 | { |
904 | for (i = 0; task_data->auth_info[i] != NULL((void*)0); i++) |
905 | { |
906 | memset (task_data->auth_info[i], 0, strlen (task_data->auth_info[i])); |
907 | g_clear_pointer (&task_data->auth_info[i], g_free)do { _Static_assert (sizeof *(&task_data->auth_info[i] ) == sizeof (gpointer), "Expression evaluates to false"); __typeof__ ((&task_data->auth_info[i])) _pp = (&task_data-> auth_info[i]); __typeof__ (*(&task_data->auth_info[i]) ) _ptr = *_pp; *_pp = ((void*)0); if (_ptr) (g_free) (_ptr); } while (0); |
908 | } |
909 | g_clear_pointer (&task_data->auth_info, g_free)do { _Static_assert (sizeof *(&task_data->auth_info) == sizeof (gpointer), "Expression evaluates to false"); __typeof__ ((&task_data->auth_info)) _pp = (&task_data->auth_info ); __typeof__ (*(&task_data->auth_info)) _ptr = *_pp; * _pp = ((void*)0); if (_ptr) (g_free) (_ptr); } while (0); |
910 | } |
911 | |
912 | if (task_data->prompt_subscription != 0) |
913 | { |
914 | g_dbus_connection_signal_unsubscribe (task_data->dbus_connection, |
915 | task_data->prompt_subscription); |
916 | task_data->prompt_subscription = 0; |
917 | } |
918 | |
919 | if (task_data->session_path != NULL((void*)0)) |
920 | { |
921 | g_dbus_connection_call (task_data->dbus_connection, |
922 | SECRETS_BUS"org.freedesktop.secrets", |
923 | task_data->session_path, |
924 | SECRETS_IFACE ("Session")"org.freedesktop.Secret.""Session", |
925 | "Close", |
926 | NULL((void*)0), |
927 | G_VARIANT_TYPE ("()")(g_variant_type_checked_ (("()"))), |
928 | G_DBUS_CALL_FLAGS_NONE, |
929 | SECRETS_TIMEOUT5000, |
930 | NULL((void*)0), |
931 | NULL((void*)0), |
932 | NULL((void*)0)); |
933 | } |
934 | |
935 | g_clear_object (&task_data->dbus_connection)do { _Static_assert (sizeof *((&task_data->dbus_connection )) == sizeof (gpointer), "Expression evaluates to false"); __typeof__ (((&task_data->dbus_connection))) _pp = ((&task_data ->dbus_connection)); __typeof__ (*((&task_data->dbus_connection ))) _ptr = *_pp; *_pp = ((void*)0); if (_ptr) (g_object_unref ) (_ptr); } while (0); |
936 | g_clear_pointer (&task_data->session_path, g_free)do { _Static_assert (sizeof *(&task_data->session_path ) == sizeof (gpointer), "Expression evaluates to false"); __typeof__ ((&task_data->session_path)) _pp = (&task_data-> session_path); __typeof__ (*(&task_data->session_path) ) _ptr = *_pp; *_pp = ((void*)0); if (_ptr) (g_free) (_ptr); } while (0); |
937 | g_clear_object (&task_data->item_proxy)do { _Static_assert (sizeof *((&task_data->item_proxy) ) == sizeof (gpointer), "Expression evaluates to false"); __typeof__ (((&task_data->item_proxy))) _pp = ((&task_data-> item_proxy)); __typeof__ (*((&task_data->item_proxy))) _ptr = *_pp; *_pp = ((void*)0); if (_ptr) (g_object_unref) ( _ptr); } while (0); |
938 | } |
939 | |
940 | /** |
941 | * ctk_cups_secrets_service_query_task: |
942 | * @source_object: Source object for this task |
943 | * @cancellable: Cancellable to cancel this task |
944 | * @callback: Callback to call once the query is finished |
945 | * @user_data: The user_data passed to the callback |
946 | * @printer_uri: URI of the printer |
947 | * @auth_info_required: Info required for authentication |
948 | * |
949 | * Checks if a secrets service as described by the secrets-service standard |
950 | * is available and if so it tries to find the authentication info in the |
951 | * default collection of the service. |
952 | * |
953 | * This is the entry point to a chain of async calls to open a session, |
954 | * search the secret, unlock the collection (if necessary) and finally |
955 | * to lookup the secret. |
956 | * |
957 | * See: http://standards.freedesktop.org/secret-service/ for documentation |
958 | * of the used API. |
959 | */ |
960 | void |
961 | ctk_cups_secrets_service_query_task (gpointer source_object, |
962 | GCancellable *cancellable, |
963 | GAsyncReadyCallback callback, |
964 | gpointer user_data, |
965 | const gchar *printer_uri, |
966 | gchar **auth_info_required) |
967 | { |
968 | GTask *task; |
969 | SecretsServiceData *task_data; |
970 | |
971 | task_data = g_new0 (SecretsServiceData, 1)((SecretsServiceData *) g_malloc0_n ((1), sizeof (SecretsServiceData ))); |
972 | task_data->action = SECRETS_SERVICE_ACTION_QUERY; |
973 | task_data->printer_uri = g_strdup (printer_uri)g_strdup_inline (printer_uri); |
974 | task_data->auth_info_required = g_strdupv (auth_info_required); |
975 | |
976 | task = g_task_new (source_object, cancellable, callback, user_data); |
977 | |
978 | g_task_set_task_data (task, task_data, cleanup_task_data); |
979 | |
980 | g_bus_get (G_BUS_TYPE_SESSION, cancellable, |
981 | get_connection_cb, task); |
982 | } |
983 | |
984 | static void |
985 | store_done_cb (GObject *source_object G_GNUC_UNUSED__attribute__ ((__unused__)), |
986 | GAsyncResult *res, |
987 | gpointer user_data G_GNUC_UNUSED__attribute__ ((__unused__))) |
988 | { |
989 | GTask *task = (GTask *) res; |
990 | GError *error = NULL((void*)0); |
991 | |
992 | g_task_propagate_pointer (task, &error); |
993 | |
994 | if (error != NULL((void*)0)) |
995 | { |
996 | CTK_NOTE (PRINTING,do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) { g_print ("Failed to store auth info: %s\n", error->message ); }; } while (0) |
997 | g_print ("Failed to store auth info: %s\n", error->message))do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) { g_print ("Failed to store auth info: %s\n", error->message ); }; } while (0); |
998 | g_error_free (error); |
999 | } |
1000 | |
1001 | g_object_unref (task); |
1002 | CTK_NOTE (PRINTING,do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) { g_print ("ctk_cups_secrets_service_store finished.\n"); }; } while (0) |
1003 | g_print ("ctk_cups_secrets_service_store finished.\n"))do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) { g_print ("ctk_cups_secrets_service_store finished.\n"); }; } while (0); |
1004 | } |
1005 | |
1006 | /** |
1007 | * ctk_cups_secrets_service_store: |
1008 | * @auth_info: Auth info that should be stored |
1009 | * @auth_info_labels: The keys to use for the auth info |
1010 | * @printer_uri: URI of the printer |
1011 | * |
1012 | * Tries to store the auth_info in a secrets service. |
1013 | */ |
1014 | void |
1015 | ctk_cups_secrets_service_store (gchar **auth_info, |
1016 | gchar **auth_info_labels, |
1017 | const gchar *printer_uri) |
1018 | { |
1019 | GTask *task; |
1020 | SecretsServiceData *task_data; |
1021 | |
1022 | if (auth_info == NULL((void*)0) || auth_info_labels == NULL((void*)0) || printer_uri == NULL((void*)0)) |
1023 | { |
1024 | CTK_NOTE (PRINTING,do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) { g_print ("Invalid call to ctk_cups_secrets_service_store.\n" ); }; } while (0) |
1025 | g_print ("Invalid call to ctk_cups_secrets_service_store.\n"))do { if ((ctk_get_debug_flags () & CTK_DEBUG_PRINTING)) { g_print ("Invalid call to ctk_cups_secrets_service_store.\n" ); }; } while (0); |
1026 | return; |
1027 | } |
1028 | |
1029 | task_data = g_new0 (SecretsServiceData, 1)((SecretsServiceData *) g_malloc0_n ((1), sizeof (SecretsServiceData ))); |
1030 | task_data->action = SECRETS_SERVICE_ACTION_STORE; |
1031 | task_data->printer_uri = g_strdup (printer_uri)g_strdup_inline (printer_uri); |
1032 | task_data->auth_info = g_strdupv (auth_info); |
1033 | task_data->auth_info_labels = g_strdupv (auth_info_labels); |
1034 | |
1035 | task = g_task_new (NULL((void*)0), NULL((void*)0), store_done_cb, NULL((void*)0)); |
1036 | |
1037 | g_task_set_task_data (task, task_data, cleanup_task_data); |
1038 | |
1039 | g_bus_get (G_BUS_TYPE_SESSION, NULL((void*)0), |
1040 | get_connection_cb, task); |
1041 | } |