Bug Summary

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

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name ctkcupssecretsutils.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/modules/printbackends/cups -resource-dir /usr/lib/llvm-16/lib/clang/16 -D HAVE_CONFIG_H -I . -I ../../.. -I ../../.. -I ../../../ctk -I ../../../ctk -I ../../../cdk -I ../../../cdk -I /usr/include/colord-1 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/libmount -I /usr/include/blkid -D CTK_COMPILATION -D CTK_PRINT_BACKEND_ENABLE_UNSUPPORTED -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/atk-1.0 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/webp -I /usr/include/at-spi2-atk/2.0 -I /usr/include/at-spi-2.0 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -I /usr/include/gio-unix-2.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/pango-1.0 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -D G_ENABLE_DEBUG -D G_ENABLE_CONSISTENCY_CHECKS -D GLIB_MIN_REQUIRED_VERSION=GLIB_VERSION_2_66 -D GLIB_MAX_ALLOWED_VERSION=GLIB_VERSION_2_66 -D PIC -internal-isystem /usr/lib/llvm-16/lib/clang/16/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fdebug-compilation-dir=/rootdir/modules/printbackends/cups -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-09-19-171836-43636-1 -x c ctkcupssecretsutils.c
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
31typedef enum
32{
33 SECRETS_SERVICE_ACTION_QUERY,
34 SECRETS_SERVICE_ACTION_STORE
35} SecretsServiceAction;
36
37typedef 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 */
62static GVariant *
63create_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
98static void
99get_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
228fail:
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
242static void
243create_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
273static void
274do_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
365static void
366prompt_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
426static void
427prompt_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
464static void
465unlock_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
529static void
530unlock_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
586static void
587item_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
662static void
663search_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
735static void
736open_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
832static void
833get_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 */
877guint
878ctk_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
891void
892cleanup_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 */
960void
961ctk_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
984static void
985store_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 */
1014void
1015ctk_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}