1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
2 *
3 * Copyright (C) 2007-2010 David Zeuthen <zeuthen@gmail.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 *
19 */
20
21 #include "config.h"
22 #include <glib/gi18n-lib.h>
23 #include <glib/gstdio.h>
24 #include <gio/gunixfdlist.h>
25
26 #include <stdio.h>
27
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <fcntl.h>
31 #include <errno.h>
32 #include <pwd.h>
33
34 #include <limits.h>
35 #include <stdlib.h>
36
37 #include <blockdev/blockdev.h>
38
39 #include "udisksdaemon.h"
40 #include "udisksdaemonutil.h"
41 #include "udisksstate.h"
42 #include "udiskslogging.h"
43 #include "udiskslinuxdevice.h"
44 #include "udiskslinuxprovider.h"
45 #include "udiskslinuxblockobject.h"
46 #include "udiskslinuxdriveobject.h"
47
48 #if defined(HAVE_LIBSYSTEMD_LOGIN)
49 #include <systemd/sd-daemon.h>
50 #include <systemd/sd-login.h>
51 #endif
52
53 #if defined(HAVE_ELOGIND) && !defined(HAVE_LIBSYSTEMD_LOGIN)
54 #include <elogind/sd-login.h>
55 /* re-use HAVE_LIBSYSTEMD_LOGIN to not clutter the source file */
56 #define HAVE_LIBSYSTEMD_LOGIN 1
57 #endif
58
59 #if defined(HAVE_LIBSYSTEMD_LOGIN)
60 #define LOGIND_AVAILABLE() (access("/run/systemd/seats/", F_OK) >= 0)
61 #endif
62
63 /**
64 * SECTION:udisksdaemonutil
65 * @title: Utilities
66 * @short_description: Various utility routines
67 *
68 * Various utility routines.
69 */
70
71
72 /**
73 * udisks_string_concat:
74 * @a: First part
75 * @b: Second part
76 *
77 * Returns: A new #GString holding the concatenation of the inputs.
78 */
udisks_string_concat(GString * a,GString * b)79 GString* udisks_string_concat (GString *a,
80 GString *b)
81 {
82 GString *result;
83 result = g_string_sized_new (a->len + b->len);
84 g_string_append_len (result, a->str, a->len);
85 g_string_append_len (result, b->str, b->len);
86 return result;
87 }
88
89 gchar *
udisks_daemon_util_subst_str(const gchar * str,const gchar * from,const gchar * to)90 udisks_daemon_util_subst_str (const gchar *str,
91 const gchar *from,
92 const gchar *to)
93 {
94 gchar **parts;
95 gchar *result;
96
97 parts = g_strsplit (str, from, 0);
98 result = g_strjoinv (to, parts);
99 g_strfreev (parts);
100 return result;
101 }
102
103 /**
104 * udisks_daemon_util_subst_str_and_escape:
105 * @str: A command string with variables to replace.
106 * @from: A variable name that should be expanded.
107 * @to: The value for that variable. Will be escaped for shells before
108 * substitution.
109 *
110 * Returns: The command string with the substituted variable.
111 */
112 gchar *
udisks_daemon_util_subst_str_and_escape(const gchar * str,const gchar * from,const gchar * to)113 udisks_daemon_util_subst_str_and_escape (const gchar *str,
114 const gchar *from,
115 const gchar *to)
116 {
117 gchar *quoted_and_escaped;
118 gchar *ret;
119 quoted_and_escaped = g_shell_quote (to);
120 ret = udisks_daemon_util_subst_str (str, from, quoted_and_escaped);
121 g_free (quoted_and_escaped);
122 return ret;
123 }
124
125 /**
126 * udisks_string_wipe_and_free:
127 * @string: A string with potentially unsafe content or %NULL.
128 *
129 * Wipes the buffer and frees the string.
130 */
udisks_string_wipe_and_free(GString * string)131 void udisks_string_wipe_and_free (GString *string)
132 {
133 if (string != NULL)
134 {
135 memset (string->str, '\0', string->len);
136 g_string_free (string, TRUE);
137 }
138 }
139
140 /**
141 * udisks_variant_lookup_binary:
142 * @dict: A dictionary #GVariant.
143 * @name: The name of the item to lookup.
144 * @out_text: (out): Return location for the binary text as #GString.
145 *
146 * Looks up binary data in a dictionary #GVariant and returns it as #GString.
147 *
148 * If the value is a bytestring ("ay"), it can contain arbitrary binary data
149 * including '\0' values. If the value is a string ("s"), @out_text does not
150 * include the terminating '\0' character.
151 *
152 * Returns: %TRUE if @dict contains an item @name of type "ay" or "s" that was
153 * successfully stored in @out_text, and %FALSE otherwise.
154 */
155 gboolean
udisks_variant_lookup_binary(GVariant * dict,const gchar * name,GString ** out_text)156 udisks_variant_lookup_binary (GVariant *dict,
157 const gchar *name,
158 GString **out_text)
159 {
160 GVariant* item = g_variant_lookup_value (dict, name, NULL);
161 if (item)
162 {
163 gboolean ret = udisks_variant_get_binary (item, out_text);
164 g_variant_unref (item);
165
166 return ret;
167 }
168
169 return FALSE;
170 }
171
172 /**
173 * udisks_variant_get_binary:
174 * @value: A #GVariant of type "ay" or "s".
175 * @out_text: (out): Return location for the binary text as #GString.
176 *
177 * Gets binary data contained in a BYTEARRAY or STRING #GVariant and returns
178 * it as a #GString.
179 *
180 * If the value is a bytestring ("ay"), it can contain arbitrary binary data
181 * including '\0' values. If the value is a string ("s"), @out_text does not
182 * include the terminating '\0' character.
183 *
184 * Returns: %TRUE if @value is a bytestring or string #GVariant and was
185 * successfully stored in @out_text, and %FALSE otherwise.
186 */
187 gboolean
udisks_variant_get_binary(GVariant * value,GString ** out_text)188 udisks_variant_get_binary (GVariant *value,
189 GString **out_text)
190 {
191 const gchar* str = NULL;
192 gsize size = 0;
193
194 if (g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
195 str = g_variant_get_string (value, &size);
196 else if (g_variant_is_of_type (value, G_VARIANT_TYPE_BYTESTRING))
197 str = g_variant_get_fixed_array (value, &size, sizeof (guchar));
198
199 if (str)
200 {
201 *out_text = g_string_new_len (str, size);
202 return TRUE;
203 }
204
205 return FALSE;
206 }
207
208
209 /**
210 * udisks_decode_udev_string:
211 * @str: An udev-encoded string or %NULL.
212 * @fallback_str: String to use when @str can't be converted to a valid UTF-8 string.
213 *
214 * Unescapes sequences like \x20 to " " and ensures the returned string is valid UTF-8.
215 *
216 * If the string is not valid UTF-8, try as hard as possible to convert to UTF-8.
217 *
218 * If %NULL is passed, then %NULL is returned.
219 *
220 * See udev_util_encode_string() in libudev/libudev-util.c in the udev
221 * tree for what kinds of strings can be used.
222 *
223 * Returns: A valid UTF-8 string that must be freed with g_free().
224 */
225 gchar *
udisks_decode_udev_string(const gchar * str,const gchar * fallback_str)226 udisks_decode_udev_string (const gchar *str, const gchar *fallback_str)
227 {
228 GString *s;
229 gchar *ret;
230 const gchar *end_valid;
231 guint n;
232
233 if (str == NULL)
234 {
235 ret = NULL;
236 goto out;
237 }
238
239 s = g_string_new (NULL);
240 for (n = 0; str[n] != '\0'; n++)
241 {
242 if (str[n] == '\\')
243 {
244 gint val;
245
246 if (str[n + 1] != 'x' || str[n + 2] == '\0' || str[n + 3] == '\0')
247 {
248 udisks_warning ("**** NOTE: malformed encoded string `%s'", str);
249 break;
250 }
251
252 val = (g_ascii_xdigit_value (str[n + 2]) << 4) | g_ascii_xdigit_value (str[n + 3]);
253
254 g_string_append_c (s, val);
255
256 n += 3;
257 }
258 else
259 {
260 g_string_append_c (s, str[n]);
261 }
262 }
263
264 if (!g_utf8_validate (s->str, -1, &end_valid))
265 {
266 udisks_warning ("The string `%s' is not valid UTF-8. Invalid characters begins at `%s'", s->str, end_valid);
267 if (fallback_str)
268 {
269 udisks_info ("Invalid string `%s' replaced by `%s'", s->str, fallback_str);
270 ret = g_strdup (fallback_str);
271 g_string_free (s, TRUE);
272 }
273 else
274 {
275 ret = g_strndup (s->str, end_valid - s->str);
276 g_string_free (s, TRUE);
277 }
278 }
279 else
280 {
281 ret = g_string_free (s, FALSE);
282 }
283
284 out:
285 return ret;
286 }
287
288 /**
289 * udisks_safe_append_to_object_path:
290 * @str: A #GString to append to.
291 * @s: A UTF-8 string.
292 *
293 * Appends @s to @str in a way such that only characters that can be
294 * used in a D-Bus object path will be used. E.g. a character not in
295 * <literal>[A-Z][a-z][0-9]_</literal> will be escaped as _HEX where
296 * HEX is a two-digit hexadecimal number.
297 *
298 * Note that his mapping is not bijective - e.g. you cannot go back
299 * to the original string.
300 */
301 void
udisks_safe_append_to_object_path(GString * str,const gchar * s)302 udisks_safe_append_to_object_path (GString *str,
303 const gchar *s)
304 {
305 guint n;
306 for (n = 0; s[n] != '\0'; n++)
307 {
308 gint c = s[n];
309 /* D-Bus spec sez:
310 *
311 * Each element must only contain the ASCII characters "[A-Z][a-z][0-9]_"
312 */
313 if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '_')
314 {
315 g_string_append_c (str, c);
316 }
317 else
318 {
319 /* Escape bytes not in [A-Z][a-z][0-9] as _<hex-with-two-digits> */
320 g_string_append_printf (str, "_%02x", (guint) c);
321 }
322 }
323 }
324
325 /**
326 * udisks_g_object_ref_foreach:
327 * @object: A #GObject to ref.
328 * @unused: Unused parameter.
329 *
330 * This is a helper function for g_list_foreach. It expects a function
331 * that takes two parameters but the standard g_object_ref takes just one
332 * and using it makes gcc sad. So this function just calls g_object_ref
333 * and throws away the second parameter.
334 */
335 void
udisks_g_object_ref_foreach(gpointer object,gpointer unused)336 udisks_g_object_ref_foreach (gpointer object, gpointer unused)
337 {
338 g_return_if_fail (G_IS_OBJECT (object));
339 g_object_ref (G_OBJECT (object));
340 return;
341 }
342
343 /**
344 * udisks_g_object_ref_copy:
345 * @object: A #GObject to ref.
346 * @unused: Unused parameter.
347 *
348 * This is a helper function for g_list_copy_deep. It expects copy function
349 * that takes two parameters but the standard g_object_ref takes just one
350 * and using it makes gcc sad. So this function just calls g_object_ref
351 * and throws away the second parameter.
352 */
353 void *
udisks_g_object_ref_copy(gconstpointer object,gpointer unused)354 udisks_g_object_ref_copy (gconstpointer object, gpointer unused)
355 {
356 g_return_val_if_fail (G_IS_OBJECT (object), NULL);
357 return g_object_ref (G_OBJECT (object));
358 }
359
360 /**
361 * udisks_daemon_util_block_get_size:
362 * @device: A #GUdevDevice for a top-level block device.
363 * @out_media_available: (out): Return location for whether media is available or %NULL.
364 * @out_media_change_detected: (out): Return location for whether media change is detected or %NULL.
365 *
366 * Gets the size of the @device top-level block device, checking for media in the process
367 *
368 * Returns: The size of @device or 0 if no media is available or if unknown.
369 */
370 guint64
udisks_daemon_util_block_get_size(GUdevDevice * device,gboolean * out_media_available,gboolean * out_media_change_detected)371 udisks_daemon_util_block_get_size (GUdevDevice *device,
372 gboolean *out_media_available,
373 gboolean *out_media_change_detected)
374 {
375 gboolean media_available = FALSE;
376 gboolean media_change_detected = TRUE;
377 guint64 size = 0;
378
379 /* figuring out if media is available is a bit tricky */
380 if (g_udev_device_get_sysfs_attr_as_boolean (device, "removable"))
381 {
382 /* never try to open optical drives (might cause the door to close) or
383 * floppy drives (makes noise)
384 */
385 if (g_udev_device_get_property_as_boolean (device, "ID_DRIVE_FLOPPY"))
386 {
387 /* assume media available */
388 media_available = TRUE;
389 media_change_detected = FALSE;
390 }
391 else if (g_udev_device_get_property_as_boolean (device, "ID_CDROM"))
392 {
393 /* Rely on (careful) work already done by udev's cdrom_id prober */
394 if (g_udev_device_get_property_as_boolean (device, "ID_CDROM_MEDIA"))
395 media_available = TRUE;
396 }
397 else
398 {
399 gint fd;
400 /* For the general case, just rely on open(2) failing with
401 * ENOMEDIUM if no medium is inserted
402 */
403 fd = open (g_udev_device_get_device_file (device), O_RDONLY);
404 if (fd >= 0)
405 {
406 media_available = TRUE;
407 close (fd);
408 }
409 }
410 }
411 else
412 {
413 /* not removable, so media is implicitly available */
414 media_available = TRUE;
415 }
416
417 if (media_available && size == 0 && media_change_detected)
418 size = g_udev_device_get_sysfs_attr_as_uint64 (device, "size") * 512;
419
420 if (out_media_available != NULL)
421 *out_media_available = media_available;
422
423 if (out_media_change_detected != NULL)
424 *out_media_change_detected = media_change_detected;
425
426 return size;
427 }
428
429
430 /**
431 * udisks_daemon_util_resolve_link:
432 * @path: A path
433 * @name: Name of a symlink in @path.
434 *
435 * Resolves the symlink @path/@name.
436 *
437 * Returns: A canonicalized absolute pathname or %NULL if the symlink
438 * could not be resolved. Free with g_free().
439 */
440 gchar *
udisks_daemon_util_resolve_link(const gchar * path,const gchar * name)441 udisks_daemon_util_resolve_link (const gchar *path,
442 const gchar *name)
443 {
444 gchar *full_path;
445 gchar link_path[PATH_MAX];
446 gchar resolved_path[PATH_MAX];
447 gssize num;
448 gboolean found_it;
449
450 found_it = FALSE;
451
452 full_path = g_build_filename (path, name, NULL);
453
454 num = readlink (full_path, link_path, sizeof(link_path) - 1);
455 if (num != -1)
456 {
457 char *absolute_path;
458 gchar *full_path_dir;
459
460 link_path[num] = '\0';
461
462 full_path_dir = g_path_get_dirname (full_path);
463 absolute_path = g_build_filename (full_path_dir, link_path, NULL);
464 g_free (full_path_dir);
465 if (realpath (absolute_path, resolved_path) != NULL)
466 {
467 found_it = TRUE;
468 }
469 g_free (absolute_path);
470 }
471 g_free (full_path);
472
473 if (found_it)
474 return g_strdup (resolved_path);
475 else
476 return NULL;
477 }
478
479 /**
480 * udisks_daemon_util_resolve_links:
481 * @path: A path
482 * @dir_name: Name of a directory in @path holding symlinks.
483 *
484 * Resolves all symlinks in @path/@dir_name. This can be used to
485 * easily walk e.g. holders or slaves of block devices.
486 *
487 * Returns: An array of canonicalized absolute pathnames. Free with g_strfreev().
488 */
489 gchar **
udisks_daemon_util_resolve_links(const gchar * path,const gchar * dir_name)490 udisks_daemon_util_resolve_links (const gchar *path,
491 const gchar *dir_name)
492 {
493 gchar *s;
494 GDir *dir;
495 const gchar *name;
496 GPtrArray *p;
497
498 p = g_ptr_array_new ();
499
500 s = g_build_filename (path, dir_name, NULL);
501 dir = g_dir_open (s, 0, NULL);
502 if (dir == NULL)
503 goto out;
504 while ((name = g_dir_read_name (dir)) != NULL)
505 {
506 gchar *resolved;
507 resolved = udisks_daemon_util_resolve_link (s, name);
508 if (resolved != NULL)
509 g_ptr_array_add (p, resolved);
510 }
511 g_ptr_array_add (p, NULL);
512
513 out:
514 if (dir != NULL)
515 g_dir_close (dir);
516 g_free (s);
517
518 return (gchar **) g_ptr_array_free (p, FALSE);
519 }
520
521
522 /**
523 * udisks_daemon_util_setup_by_user:
524 * @daemon: A #UDisksDaemon.
525 * @object: The #GDBusObject that the call is on or %NULL.
526 * @user: The user in question.
527 *
528 * Checks whether the device represented by @object (if any) has been
529 * setup by @user.
530 *
531 * Returns: %TRUE if @object has been set-up by @user, %FALSE if not.
532 */
533 gboolean
udisks_daemon_util_setup_by_user(UDisksDaemon * daemon,UDisksObject * object,uid_t user)534 udisks_daemon_util_setup_by_user (UDisksDaemon *daemon,
535 UDisksObject *object,
536 uid_t user)
537 {
538 gboolean ret;
539 UDisksBlock *block = NULL;
540 UDisksPartition *partition = NULL;
541 UDisksState *state;
542 uid_t setup_by_user;
543 UDisksObject *crypto_object;
544
545 ret = FALSE;
546
547 state = udisks_daemon_get_state (daemon);
548 block = udisks_object_get_block (object);
549 if (block == NULL)
550 goto out;
551 partition = udisks_object_get_partition (object);
552
553 /* loop devices */
554 if (udisks_state_has_loop (state, udisks_block_get_device (block), &setup_by_user))
555 {
556 if (setup_by_user == user)
557 {
558 ret = TRUE;
559 goto out;
560 }
561 }
562
563 /* partition of a loop device */
564 if (partition != NULL)
565 {
566 UDisksObject *partition_object = NULL;
567 partition_object = udisks_daemon_find_object (daemon, udisks_partition_get_table (partition));
568 if (partition_object != NULL)
569 {
570 if (udisks_daemon_util_setup_by_user (daemon, partition_object, user))
571 {
572 ret = TRUE;
573 g_object_unref (partition_object);
574 goto out;
575 }
576 g_object_unref (partition_object);
577 }
578 }
579
580 /* LUKS devices */
581 crypto_object = udisks_daemon_find_object (daemon, udisks_block_get_crypto_backing_device (block));
582 if (crypto_object != NULL)
583 {
584 UDisksBlock *crypto_block;
585 crypto_block = udisks_object_peek_block (crypto_object);
586 if (udisks_state_find_unlocked_crypto_dev (state,
587 udisks_block_get_device_number (crypto_block),
588 &setup_by_user))
589 {
590 if (setup_by_user == user)
591 {
592 ret = TRUE;
593 g_object_unref (crypto_object);
594 goto out;
595 }
596 }
597 g_object_unref (crypto_object);
598 }
599
600 /* MDRaid devices */
601 if (g_strcmp0 (udisks_block_get_mdraid (block), "/") != 0)
602 {
603 uid_t started_by_user;
604 if (udisks_state_has_mdraid (state, udisks_block_get_device_number (block), &started_by_user))
605 {
606 if (started_by_user == user)
607 {
608 ret = TRUE;
609 goto out;
610 }
611 }
612 }
613
614 out:
615 g_clear_object (&partition);
616 g_clear_object (&block);
617 return ret;
618 }
619
620 /* Need this until we can depend on a libpolkit with this bugfix
621 *
622 * http://cgit.freedesktop.org/polkit/commit/?h=wip/js-rule-files&id=224f7b892478302dccbe7e567b013d3c73d376fd
623 */
624 static void
_safe_polkit_details_insert(PolkitDetails * details,const gchar * key,const gchar * value)625 _safe_polkit_details_insert (PolkitDetails *details, const gchar *key, const gchar *value)
626 {
627 if (value != NULL && strlen (value) > 0)
628 polkit_details_insert (details, key, value);
629 }
630
631 static void
_safe_polkit_details_insert_int(PolkitDetails * details,const gchar * key,gint value)632 _safe_polkit_details_insert_int (PolkitDetails *details, const gchar *key, gint value)
633 {
634 gchar buf[32];
635 snprintf (buf, sizeof buf, "%d", value);
636 polkit_details_insert (details, key, buf);
637 }
638
639 static void
_safe_polkit_details_insert_uint64(PolkitDetails * details,const gchar * key,guint64 value)640 _safe_polkit_details_insert_uint64 (PolkitDetails *details, const gchar *key, guint64 value)
641 {
642 gchar buf[32];
643 snprintf (buf, sizeof buf, "0x%08llx", (unsigned long long int) value);
644 polkit_details_insert (details, key, buf);
645 }
646
647 static gboolean
check_authorization_no_polkit(UDisksDaemon * daemon,UDisksObject * object,const gchar * action_id,GVariant * options,const gchar * message,GDBusMethodInvocation * invocation,GError ** error)648 check_authorization_no_polkit (UDisksDaemon *daemon,
649 UDisksObject *object,
650 const gchar *action_id,
651 GVariant *options,
652 const gchar *message,
653 GDBusMethodInvocation *invocation,
654 GError **error)
655 {
656 gboolean ret = FALSE;
657 uid_t caller_uid = -1;
658 GError *sub_error = NULL;
659
660 if (!udisks_daemon_util_get_caller_uid_sync (daemon,
661 invocation,
662 NULL, /* GCancellable* */
663 &caller_uid,
664 &sub_error))
665 {
666 g_set_error (error,
667 UDISKS_ERROR,
668 UDISKS_ERROR_FAILED,
669 "Error getting uid for caller with bus name %s: %s (%s, %d)",
670 g_dbus_method_invocation_get_sender (invocation),
671 sub_error->message, g_quark_to_string (sub_error->domain), sub_error->code);
672 g_clear_error (&sub_error);
673 goto out;
674 }
675
676 /* only allow root */
677 if (caller_uid == 0)
678 {
679 ret = TRUE;
680 }
681 else
682 {
683 g_set_error (error,
684 UDISKS_ERROR,
685 UDISKS_ERROR_NOT_AUTHORIZED,
686 "Not authorized to perform operation (polkit authority not available and caller is not uid 0)");
687 }
688
689 out:
690 return ret;
691 }
692
693 /**
694 * udisks_daemon_util_check_authorization_sync:
695 * @daemon: A #UDisksDaemon.
696 * @object: (allow-none): The #GDBusObject that the call is on or %NULL.
697 * @action_id: The action id to check for.
698 * @options: (allow-none): A #GVariant to check for the <quote>auth.no_user_interaction</quote> option or %NULL.
699 * @message: The message to convey (use N_).
700 * @invocation: The invocation to check for.
701 *
702 * Checks if the caller represented by @invocation is authorized for
703 * the action identified by @action_id, optionally displaying @message
704 * if authentication is needed. Additionally, if the caller is not
705 * authorized, the appropriate error is already returned to the caller
706 * via @invocation.
707 *
708 * The calling thread is blocked for the duration of the authorization
709 * check which could be a very long time since it may involve
710 * presenting an authentication dialog and having a human user use
711 * it. If <quote>auth.no_user_interaction</quote> in @options is %TRUE
712 * no authentication dialog will be presented and the check is not
713 * expected to take a long time.
714 *
715 * See <xref linkend="udisks-polkit-details"/> for the variables that
716 * can be used in @message but note that not all variables can be used
717 * in all checks. For example, any check involving a #UDisksDrive or a
718 * #UDisksBlock object can safely include the fragment
719 * <quote>$(drive)</quote> since it will always expand to the name of
720 * the drive, e.g. <quote>INTEL SSDSA2MH080G1GC (/dev/sda1)</quote> or
721 * the block device file e.g. <quote>/dev/vg_lucifer/lv_root</quote>
722 * or <quote>/dev/sda1</quote>. However this won't work for operations
723 * that isn't on a drive or block device, for example calls on the
724 * <link linkend="gdbus-interface-org-freedesktop-UDisks2-Manager.top_of_page">Manager</link>
725 * object.
726 *
727 * Returns: %TRUE if caller is authorized, %FALSE if not.
728 */
729 gboolean
udisks_daemon_util_check_authorization_sync(UDisksDaemon * daemon,UDisksObject * object,const gchar * action_id,GVariant * options,const gchar * message,GDBusMethodInvocation * invocation)730 udisks_daemon_util_check_authorization_sync (UDisksDaemon *daemon,
731 UDisksObject *object,
732 const gchar *action_id,
733 GVariant *options,
734 const gchar *message,
735 GDBusMethodInvocation *invocation)
736 {
737 GError *error = NULL;
738 if (!udisks_daemon_util_check_authorization_sync_with_error (daemon,
739 object,
740 action_id,
741 options,
742 message,
743 invocation,
744 &error))
745 {
746 g_dbus_method_invocation_take_error (invocation, error);
747 return FALSE;
748 }
749
750 return TRUE;
751 }
752
753 gboolean
udisks_daemon_util_check_authorization_sync_with_error(UDisksDaemon * daemon,UDisksObject * object,const gchar * action_id,GVariant * options,const gchar * message,GDBusMethodInvocation * invocation,GError ** error)754 udisks_daemon_util_check_authorization_sync_with_error (UDisksDaemon *daemon,
755 UDisksObject *object,
756 const gchar *action_id,
757 GVariant *options,
758 const gchar *message,
759 GDBusMethodInvocation *invocation,
760 GError **error)
761 {
762 PolkitAuthority *authority = NULL;
763 PolkitSubject *subject = NULL;
764 PolkitDetails *details = NULL;
765 PolkitCheckAuthorizationFlags flags = POLKIT_CHECK_AUTHORIZATION_FLAGS_NONE;
766 PolkitAuthorizationResult *result = NULL;
767 GError *sub_error = NULL;
768 gboolean ret = FALSE;
769 UDisksBlock *block = NULL;
770 UDisksDrive *drive = NULL;
771 UDisksPartition *partition = NULL;
772 UDisksObject *block_object = NULL;
773 UDisksObject *drive_object = NULL;
774 gboolean auth_no_user_interaction = FALSE;
775 const gchar *details_device = NULL;
776 gchar *details_drive = NULL;
777
778 authority = udisks_daemon_get_authority (daemon);
779 if (authority == NULL)
780 {
781 ret = check_authorization_no_polkit (daemon, object, action_id, options, message, invocation, error);
782 goto out;
783 }
784
785 subject = polkit_system_bus_name_new (g_dbus_method_invocation_get_sender (invocation));
786 if (options != NULL)
787 {
788 g_variant_lookup (options,
789 "auth.no_user_interaction",
790 "b",
791 &auth_no_user_interaction);
792 }
793 if (!auth_no_user_interaction)
794 flags = POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION;
795
796 details = polkit_details_new ();
797 polkit_details_insert (details, "polkit.message", message);
798 polkit_details_insert (details, "polkit.gettext_domain", "udisks2");
799
800 /* Find drive associated with the block device, if any */
801 if (object != NULL)
802 {
803 block = udisks_object_get_block (object);
804 if (block != NULL)
805 {
806 block_object = g_object_ref (object);
807 drive_object = udisks_daemon_find_object (daemon, udisks_block_get_drive (block));
808 if (drive_object != NULL)
809 drive = udisks_object_get_drive (drive_object);
810 }
811
812 partition = udisks_object_get_partition (object);
813
814 if (drive == NULL)
815 drive = udisks_object_get_drive (object);
816 }
817
818 if (block != NULL)
819 details_device = udisks_block_get_preferred_device (block);
820
821 /* If we have a drive, use vendor/model in the message (in addition to Block:preferred-device) */
822 if (drive != NULL)
823 {
824 gchar *s;
825 const gchar *vendor;
826 const gchar *model;
827
828 vendor = udisks_drive_get_vendor (drive);
829 model = udisks_drive_get_model (drive);
830 if (vendor == NULL)
831 vendor = "";
832 if (model == NULL)
833 model = "";
834
835 if (strlen (vendor) > 0 && strlen (model) > 0)
836 s = g_strdup_printf ("%s %s", vendor, model);
837 else if (strlen (vendor) > 0)
838 s = g_strdup (vendor);
839 else
840 s = g_strdup (model);
841
842 if (block != NULL)
843 {
844 details_drive = g_strdup_printf ("%s (%s)", s, udisks_block_get_preferred_device (block));
845 }
846 else
847 {
848 details_drive = s;
849 s = NULL;
850 }
851 g_free (s);
852
853 _safe_polkit_details_insert (details, "drive.wwn", udisks_drive_get_wwn (drive));
854 _safe_polkit_details_insert (details, "drive.serial", udisks_drive_get_serial (drive));
855 _safe_polkit_details_insert (details, "drive.vendor", udisks_drive_get_vendor (drive));
856 _safe_polkit_details_insert (details, "drive.model", udisks_drive_get_model (drive));
857 _safe_polkit_details_insert (details, "drive.revision", udisks_drive_get_revision (drive));
858 if (udisks_drive_get_removable (drive))
859 {
860 const gchar *const *media_compat;
861 GString *media_compat_str;
862 const gchar *sep = ",";
863
864 polkit_details_insert (details, "drive.removable", "true");
865 _safe_polkit_details_insert (details, "drive.removable.bus", udisks_drive_get_connection_bus (drive));
866
867 media_compat_str = g_string_new (NULL);
868 media_compat = udisks_drive_get_media_compatibility (drive);
869 if (media_compat)
870 {
871 guint i;
872
873 for (i = 0; media_compat[i] && strlen(media_compat[i]); i++)
874 {
875 if (i)
876 g_string_append (media_compat_str, sep);
877 g_string_append (media_compat_str, media_compat[i]);
878 }
879 }
880
881 _safe_polkit_details_insert (details, "drive.removable.media", media_compat_str->str);
882 g_string_free (media_compat_str, TRUE);
883 }
884 }
885
886 if (block != NULL)
887 {
888 _safe_polkit_details_insert (details, "id.type", udisks_block_get_id_type (block));
889 _safe_polkit_details_insert (details, "id.usage", udisks_block_get_id_usage (block));
890 _safe_polkit_details_insert (details, "id.version", udisks_block_get_id_version (block));
891 _safe_polkit_details_insert (details, "id.label", udisks_block_get_id_label (block));
892 _safe_polkit_details_insert (details, "id.uuid", udisks_block_get_id_uuid (block));
893 }
894
895 if (partition != NULL)
896 {
897 _safe_polkit_details_insert_int (details, "partition.number", udisks_partition_get_number (partition));
898 _safe_polkit_details_insert (details, "partition.type", udisks_partition_get_type_ (partition));
899 _safe_polkit_details_insert_uint64 (details, "partition.flags", udisks_partition_get_flags (partition));
900 _safe_polkit_details_insert (details, "partition.name", udisks_partition_get_name (partition));
901 _safe_polkit_details_insert (details, "partition.uuid", udisks_partition_get_uuid (partition));
902 }
903
904 /* Fall back to Block:preferred-device */
905 if (details_drive == NULL && block != NULL)
906 details_drive = udisks_block_dup_preferred_device (block);
907
908 if (details_device != NULL)
909 polkit_details_insert (details, "device", details_device);
910 if (details_drive != NULL)
911 polkit_details_insert (details, "drive", details_drive);
912
913 sub_error = NULL;
914 result = polkit_authority_check_authorization_sync (authority,
915 subject,
916 action_id,
917 details,
918 flags,
919 NULL, /* GCancellable* */
920 &sub_error);
921 if (result == NULL)
922 {
923 if (sub_error->domain != POLKIT_ERROR)
924 {
925 /* assume polkit authority is not available (e.g. could be the service
926 * manager returning org.freedesktop.systemd1.Masked)
927 */
928 g_clear_error (&sub_error);
929 ret = check_authorization_no_polkit (daemon, object, action_id, options, message, invocation, error);
930 }
931 else
932 {
933 g_set_error (error,
934 UDISKS_ERROR,
935 UDISKS_ERROR_FAILED,
936 "Error checking authorization: %s (%s, %d)",
937 sub_error->message,
938 g_quark_to_string (sub_error->domain),
939 sub_error->code);
940 g_clear_error (&sub_error);
941 }
942 goto out;
943 }
944 if (!polkit_authorization_result_get_is_authorized (result))
945 {
946 if (polkit_authorization_result_get_dismissed (result))
947 g_set_error (error,
948 UDISKS_ERROR,
949 UDISKS_ERROR_NOT_AUTHORIZED_DISMISSED,
950 "The authentication dialog was dismissed");
951 else
952 g_set_error (error,
953 UDISKS_ERROR,
954 polkit_authorization_result_get_is_challenge (result) ?
955 UDISKS_ERROR_NOT_AUTHORIZED_CAN_OBTAIN :
956 UDISKS_ERROR_NOT_AUTHORIZED,
957 "Not authorized to perform operation");
958 goto out;
959 }
960
961 ret = TRUE;
962
963 out:
964 g_free (details_drive);
965 g_clear_object (&block_object);
966 g_clear_object (&drive_object);
967 g_clear_object (&block);
968 g_clear_object (&partition);
969 g_clear_object (&drive);
970 g_clear_object (&subject);
971 g_clear_object (&details);
972 g_clear_object (&result);
973 return ret;
974 }
975
976 /* ---------------------------------------------------------------------------------------------------- */
977
978 static gboolean
dbus_freedesktop_guint32_get(GDBusMethodInvocation * invocation,GCancellable * cancellable,const gchar * method,guint32 * out_value,GError ** error)979 dbus_freedesktop_guint32_get (GDBusMethodInvocation *invocation,
980 GCancellable *cancellable,
981 const gchar *method,
982 guint32 *out_value,
983 GError **error)
984 {
985 gboolean ret = FALSE;
986 GError *local_error = NULL;
987 GVariant *value;
988 guint32 fetched = 0;
989 const gchar *caller = g_dbus_method_invocation_get_sender (invocation);
990
991
992 value = g_dbus_connection_call_sync (g_dbus_method_invocation_get_connection (invocation),
993 "org.freedesktop.DBus", /* bus name */
994 "/org/freedesktop/DBus", /* object path */
995 "org.freedesktop.DBus", /* interface */
996 method, /* method */
997 g_variant_new ("(s)", caller),
998 G_VARIANT_TYPE ("(u)"),
999 G_DBUS_CALL_FLAGS_NONE,
1000 -1, /* timeout_msec */
1001 cancellable,
1002 &local_error);
1003 if (value == NULL)
1004 {
1005 g_set_error (error,
1006 UDISKS_ERROR,
1007 UDISKS_ERROR_FAILED,
1008 "Error determining uid of caller %s: %s (%s, %d)",
1009 caller,
1010 local_error->message,
1011 g_quark_to_string (local_error->domain),
1012 local_error->code);
1013 g_clear_error (&local_error);
1014 goto out;
1015 }
1016
1017 {
1018 G_STATIC_ASSERT (sizeof (uid_t) == sizeof (guint32));
1019 G_STATIC_ASSERT (sizeof (pid_t) == sizeof (guint32));
1020 }
1021
1022 g_variant_get (value, "(u)", &fetched);
1023 if (out_value != NULL)
1024 *out_value = fetched;
1025
1026 g_variant_unref (value);
1027 ret = TRUE;
1028 out:
1029 return ret;
1030 }
1031
1032 /**
1033 * udisks_daemon_util_get_user_info:
1034 * @out_gid: (out) (allow-none): Return location for resolved gid or %NULL.
1035 * @out_user_name: (out) (allow-none): Return location for resolved user name or %NULL.
1036 * @error: Return location for error.
1037 *
1038 * Gets the UNIX group and user name for a user id.
1039 *
1040 * Returns: %TRUE if the user information was obtained, %FALSE otherwise
1041 */
1042 gboolean
udisks_daemon_util_get_user_info(const uid_t uid,gid_t * out_gid,gchar ** out_user_name,GError ** error)1043 udisks_daemon_util_get_user_info (const uid_t uid,
1044 gid_t *out_gid,
1045 gchar **out_user_name,
1046 GError **error)
1047 {
1048 struct passwd pwstruct;
1049 gchar pwbuf[8192];
1050 struct passwd *pw = NULL;
1051 int rc;
1052
1053 rc = getpwuid_r (uid, &pwstruct, pwbuf, sizeof pwbuf, &pw);
1054 if (rc == 0 && pw == NULL)
1055 {
1056 g_set_error (error,
1057 UDISKS_ERROR,
1058 UDISKS_ERROR_FAILED,
1059 "User with uid %d does not exist", (gint) uid);
1060 goto out;
1061 }
1062 else if (pw == NULL)
1063 {
1064 g_set_error (error,
1065 UDISKS_ERROR,
1066 UDISKS_ERROR_FAILED,
1067 "Error looking up passwd struct for uid %d: %m", (gint) uid);
1068 goto out;
1069 }
1070
1071 if (out_gid != NULL)
1072 *out_gid = pw->pw_gid;
1073
1074 if (out_user_name != NULL)
1075 *out_user_name = g_strdup (pwstruct.pw_name);
1076
1077 return TRUE;
1078
1079 out:
1080 return FALSE;
1081 }
1082
1083 /**
1084 * udisks_daemon_util_get_caller_uid_sync:
1085 * @daemon: A #UDisksDaemon.
1086 * @invocation: A #GDBusMethodInvocation.
1087 * @cancellable: (allow-none): A #GCancellable or %NULL.
1088 * @out_uid: (out): Return location for resolved uid or %NULL.
1089 * @error: Return location for error.
1090 *
1091 * Gets the UNIX user id of the peer represented by @invocation.
1092 *
1093 * Returns: %TRUE if the user id (and possibly group id) was obtained, %FALSE otherwise
1094 */
1095 gboolean
udisks_daemon_util_get_caller_uid_sync(UDisksDaemon * daemon,GDBusMethodInvocation * invocation,GCancellable * cancellable,uid_t * out_uid,GError ** error)1096 udisks_daemon_util_get_caller_uid_sync (UDisksDaemon *daemon,
1097 GDBusMethodInvocation *invocation,
1098 GCancellable *cancellable,
1099 uid_t *out_uid,
1100 GError **error)
1101 {
1102 gboolean ret;
1103 uid_t uid;
1104
1105 /* TODO: cache this on @daemon */
1106
1107 ret = FALSE;
1108
1109 if (!dbus_freedesktop_guint32_get (invocation, cancellable,
1110 "GetConnectionUnixUser",
1111 &uid, error))
1112 {
1113 goto out;
1114 }
1115
1116 if (out_uid != NULL)
1117 *out_uid = uid;
1118
1119 ret = TRUE;
1120
1121 out:
1122 return ret;
1123 }
1124
1125 /* ---------------------------------------------------------------------------------------------------- */
1126
1127 /**
1128 * udisks_daemon_util_get_caller_pid_sync:
1129 * @daemon: A #UDisksDaemon.
1130 * @invocation: A #GDBusMethodInvocation.
1131 * @cancellable: (allow-none): A #GCancellable or %NULL.
1132 * @out_pid: (out): Return location for resolved pid or %NULL.
1133 * @error: Return location for error.
1134 *
1135 * Gets the UNIX process id of the peer represented by @invocation.
1136 *
1137 * Returns: %TRUE if the process id was obtained, %FALSE otherwise
1138 */
1139 gboolean
udisks_daemon_util_get_caller_pid_sync(UDisksDaemon * daemon,GDBusMethodInvocation * invocation,GCancellable * cancellable,pid_t * out_pid,GError ** error)1140 udisks_daemon_util_get_caller_pid_sync (UDisksDaemon *daemon,
1141 GDBusMethodInvocation *invocation,
1142 GCancellable *cancellable,
1143 pid_t *out_pid,
1144 GError **error)
1145 {
1146 /* "GetConnectionUnixProcessID" */
1147
1148 /* TODO: cache this on @daemon */
1149 /* NOTE: pid_t is a signed 32 bit, but the
1150 * GetConnectionUnixProcessID dbus method returns an unsigned */
1151
1152 return dbus_freedesktop_guint32_get (invocation, cancellable,
1153 "GetConnectionUnixProcessID",
1154 (guint32*)(out_pid), error);
1155 }
1156
1157 /* ---------------------------------------------------------------------------------------------------- */
1158
1159 /**
1160 * udisks_daemon_util_dup_object:
1161 * @interface_: (type GDBusInterface): A #GDBusInterface<!-- -->-derived instance.
1162 * @error: %NULL, or an unset #GError to set if the return value is %NULL.
1163 *
1164 * Gets the enclosing #UDisksObject for @interface, if any.
1165 *
1166 * Returns: (transfer full) (type UDisksObject): Either %NULL or a
1167 * #UDisksObject<!-- -->-derived instance that must be released with
1168 * g_object_unref().
1169 */
1170 gpointer
udisks_daemon_util_dup_object(gpointer interface_,GError ** error)1171 udisks_daemon_util_dup_object (gpointer interface_,
1172 GError **error)
1173 {
1174 gpointer ret;
1175
1176 g_return_val_if_fail (G_IS_DBUS_INTERFACE (interface_), NULL);
1177 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
1178
1179 ret = g_dbus_interface_dup_object (interface_);
1180 if (ret == NULL)
1181 {
1182 g_set_error (error,
1183 UDISKS_ERROR,
1184 UDISKS_ERROR_FAILED,
1185 "No enclosing object for interface");
1186 }
1187
1188 return ret;
1189 }
1190
1191 /**
1192 * udisks_daemon_util_on_user_seat:
1193 * @daemon: A #UDisksDaemon.
1194 * @object: The #GDBusObject that the call is on or %NULL.
1195 * @user: The user to check for.
1196 *
1197 * Checks whether the device represented by @object (if any) is plugged into
1198 * a seat where the caller represented by @user is logged in and active.
1199 *
1200 * This works if @object is a drive or a block object.
1201 *
1202 * Returns: %TRUE if @object is on the same seat as one of @user's
1203 * active sessions, %FALSE otherwise.
1204 */
1205 gboolean
udisks_daemon_util_on_user_seat(UDisksDaemon * daemon,UDisksObject * object,uid_t user)1206 udisks_daemon_util_on_user_seat (UDisksDaemon *daemon,
1207 UDisksObject *object,
1208 uid_t user)
1209 {
1210 #if !defined(HAVE_LIBSYSTEMD_LOGIN)
1211 /* if we don't have systemd, assume it's always the same seat */
1212 return TRUE;
1213 #else
1214 gboolean ret = FALSE;
1215 char *session = NULL;
1216 char *seat = NULL;
1217 const gchar *drive_seat;
1218 UDisksObject *drive_object = NULL;
1219 UDisksDrive *drive = NULL;
1220
1221 /* if we don't have logind, assume it's always the same seat */
1222 if (!LOGIND_AVAILABLE())
1223 return TRUE;
1224
1225 if (UDISKS_IS_LINUX_BLOCK_OBJECT (object))
1226 {
1227 UDisksLinuxBlockObject *linux_block_object;
1228 UDisksBlock *block;
1229 linux_block_object = UDISKS_LINUX_BLOCK_OBJECT (object);
1230 block = udisks_object_get_block (UDISKS_OBJECT (linux_block_object));
1231 if (block != NULL)
1232 {
1233 drive_object = udisks_daemon_find_object (daemon, udisks_block_get_drive (block));
1234 g_object_unref (block);
1235 }
1236 }
1237 else if (UDISKS_IS_LINUX_DRIVE_OBJECT (object))
1238 {
1239 drive_object = g_object_ref (object);
1240 }
1241
1242 if (drive_object == NULL)
1243 goto out;
1244
1245 drive = udisks_object_get_drive (UDISKS_OBJECT (drive_object));
1246 if (drive == NULL)
1247 goto out;
1248
1249 drive_seat = udisks_drive_get_seat (drive);
1250
1251 if (drive_seat != NULL && sd_uid_is_on_seat (user, TRUE, drive_seat) > 0)
1252 {
1253 ret = TRUE;
1254 goto out;
1255 }
1256
1257 out:
1258 free (seat);
1259 free (session);
1260 g_clear_object (&drive_object);
1261 g_clear_object (&drive);
1262 return ret;
1263 #endif /* HAVE_LIBSYSTEMD_LOGIN */
1264 }
1265
1266 /**
1267 * udisks_daemon_util_hexdump:
1268 * @data: Pointer to data.
1269 * @len: Length of data.
1270 *
1271 * Utility function to generate a hexadecimal representation of @len
1272 * bytes of @data.
1273 *
1274 * Returns: A multi-line string. Free with g_free() when done using it.
1275 */
1276 gchar *
udisks_daemon_util_hexdump(gconstpointer data,gsize len)1277 udisks_daemon_util_hexdump (gconstpointer data, gsize len)
1278 {
1279 const guchar *bdata = data;
1280 guint n, m;
1281 GString *ret;
1282
1283 ret = g_string_new (NULL);
1284 for (n = 0; n < len; n += 16)
1285 {
1286 g_string_append_printf (ret, "%04x: ", n);
1287
1288 for (m = n; m < n + 16; m++)
1289 {
1290 if (m > n && (m%4) == 0)
1291 g_string_append_c (ret, ' ');
1292 if (m < len)
1293 g_string_append_printf (ret, "%02x ", (guint) bdata[m]);
1294 else
1295 g_string_append (ret, " ");
1296 }
1297
1298 g_string_append (ret, " ");
1299
1300 for (m = n; m < len && m < n + 16; m++)
1301 g_string_append_c (ret, g_ascii_isprint (bdata[m]) ? bdata[m] : '.');
1302
1303 g_string_append_c (ret, '\n');
1304 }
1305
1306 return g_string_free (ret, FALSE);
1307 }
1308
1309 /**
1310 * udisks_daemon_util_hexdump_debug:
1311 * @data: Pointer to data.
1312 * @len: Length of data.
1313 *
1314 * Utility function to dumps the hexadecimal representation of @len
1315 * bytes of @data generated with udisks_daemon_util_hexdump() using
1316 * udisks_debug().
1317 */
1318 void
udisks_daemon_util_hexdump_debug(gconstpointer data,gsize len)1319 udisks_daemon_util_hexdump_debug (gconstpointer data, gsize len)
1320 {
1321 gchar *s = udisks_daemon_util_hexdump (data, len);
1322 udisks_debug ("Hexdump of %" G_GSIZE_FORMAT " bytes:\n%s", len, s);
1323 g_free (s);
1324 }
1325
1326 /* ---------------------------------------------------------------------------------------------------- */
1327
1328 /**
1329 * udisks_daemon_util_file_set_contents:
1330 * @filename: (type filename): Name of a file to write @contents to, in the GLib file name encoding.
1331 * @contents: (array length=length) (element-type guint8): String to write to the file.
1332 * @contents_len: Length of @contents, or -1 if @contents is a NUL-terminated string.
1333 * @mode_for_new_file: Mode for new file.
1334 * @error: Return location for a #GError, or %NULL.
1335 *
1336 * Like g_file_set_contents() but preserves the mode of the file if it
1337 * already exists and sets it to @mode_for_new_file otherwise.
1338 *
1339 * Return value: %TRUE on success, %FALSE if an error occurred
1340 */
1341 gboolean
udisks_daemon_util_file_set_contents(const gchar * filename,const gchar * contents,gssize contents_len,gint mode_for_new_file,GError ** error)1342 udisks_daemon_util_file_set_contents (const gchar *filename,
1343 const gchar *contents,
1344 gssize contents_len,
1345 gint mode_for_new_file,
1346 GError **error)
1347 {
1348 gboolean ret;
1349 struct stat statbuf;
1350 gint mode;
1351 gchar *tmpl;
1352 gint fd;
1353 FILE *f;
1354
1355 ret = FALSE;
1356 tmpl = NULL;
1357
1358 if (stat (filename, &statbuf) != 0)
1359 {
1360 if (errno == ENOENT)
1361 {
1362 mode = mode_for_new_file;
1363 }
1364 else
1365 {
1366 g_set_error (error,
1367 G_IO_ERROR,
1368 g_io_error_from_errno (errno),
1369 "Error stat(2)'ing %s: %m",
1370 filename);
1371 goto out;
1372 }
1373 }
1374 else
1375 {
1376 mode = statbuf.st_mode;
1377 }
1378
1379 tmpl = g_strdup_printf ("%s.XXXXXX", filename);
1380 fd = g_mkstemp_full (tmpl, O_RDWR, mode);
1381 if (fd == -1)
1382 {
1383 g_set_error (error,
1384 G_IO_ERROR,
1385 g_io_error_from_errno (errno),
1386 "Error creating temporary file: %m");
1387 goto out;
1388 }
1389
1390 f = fdopen (fd, "w");
1391 if (f == NULL)
1392 {
1393 g_set_error (error,
1394 G_IO_ERROR,
1395 g_io_error_from_errno (errno),
1396 "Error calling fdopen: %m");
1397 g_unlink (tmpl);
1398 goto out;
1399 }
1400
1401 if (contents_len < 0 )
1402 contents_len = strlen (contents);
1403 if (fwrite (contents, 1, contents_len, f) != (gsize) contents_len)
1404 {
1405 g_set_error (error,
1406 G_IO_ERROR,
1407 g_io_error_from_errno (errno),
1408 "Error calling fwrite on temp file: %m");
1409 fclose (f);
1410 g_unlink (tmpl);
1411 goto out;
1412 }
1413
1414 if (fsync (fileno (f)) != 0)
1415 {
1416 g_set_error (error,
1417 G_IO_ERROR,
1418 g_io_error_from_errno (errno),
1419 "Error calling fsync on temp file: %m");
1420 fclose (f);
1421 g_unlink (tmpl);
1422 goto out;
1423 }
1424 fclose (f);
1425
1426 if (rename (tmpl, filename) != 0)
1427 {
1428 g_set_error (error,
1429 G_IO_ERROR,
1430 g_io_error_from_errno (errno),
1431 "Error renaming temp file to final file: %m");
1432 g_unlink (tmpl);
1433 goto out;
1434 }
1435
1436 ret = TRUE;
1437
1438 out:
1439 g_free (tmpl);
1440 return ret;
1441 }
1442
1443 /* ---------------------------------------------------------------------------------------------------- */
1444
1445 /**
1446 * UDisksInhibitCookie:
1447 *
1448 * Opaque data structure used in udisks_daemon_util_inhibit_system_sync() and
1449 * udisks_daemon_util_uninhibit_system_sync().
1450 */
1451 struct UDisksInhibitCookie
1452 {
1453 /*< private >*/
1454 guint32 magic;
1455 #ifdef HAVE_LIBSYSTEMD_LOGIN
1456 gint fd;
1457 #endif
1458 };
1459
1460 /**
1461 * udisks_daemon_util_inhibit_system_sync:
1462 * @reason: A human readable explanation of why the system is being inhibited.
1463 *
1464 * Tries to inhibit the system.
1465 *
1466 * Right now only
1467 * <ulink url="http://www.freedesktop.org/wiki/Software/systemd/inhibit">systemd</ulink>
1468 * inhibitors are supported but other inhibitors can be added in the future.
1469 *
1470 * Returns: A cookie that can be used with udisks_daemon_util_uninhibit_system_sync().
1471 */
1472 UDisksInhibitCookie *
udisks_daemon_util_inhibit_system_sync(const gchar * reason)1473 udisks_daemon_util_inhibit_system_sync (const gchar *reason)
1474 {
1475 #ifdef HAVE_LIBSYSTEMD_LOGIN
1476 UDisksInhibitCookie *ret = NULL;
1477 GDBusConnection *connection = NULL;
1478 GVariant *value = NULL;
1479 GUnixFDList *fd_list = NULL;
1480 gint32 index = -1;
1481 GError *error = NULL;
1482
1483 g_return_val_if_fail (reason != NULL, NULL);
1484
1485 connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
1486 if (connection == NULL)
1487 {
1488 udisks_critical ("Error getting system bus: %s (%s, %d)",
1489 error->message, g_quark_to_string (error->domain), error->code);
1490 g_clear_error (&error);
1491 goto out;
1492 }
1493
1494 value = g_dbus_connection_call_with_unix_fd_list_sync (connection,
1495 "org.freedesktop.login1",
1496 "/org/freedesktop/login1",
1497 "org.freedesktop.login1.Manager",
1498 "Inhibit",
1499 g_variant_new ("(ssss)",
1500 "sleep:shutdown:idle", /* what */
1501 "Disk Manager", /* who */
1502 reason, /* why */
1503 "block"), /* mode */
1504 G_VARIANT_TYPE ("(h)"),
1505 G_DBUS_CALL_FLAGS_NONE,
1506 -1, /* default timeout */
1507 NULL, /* fd_list */
1508 &fd_list, /* out_fd_list */
1509 NULL, /* GCancellable */
1510 &error);
1511 if (value == NULL)
1512 {
1513 udisks_critical ("Error inhibiting: %s (%s, %d)",
1514 error->message, g_quark_to_string (error->domain), error->code);
1515 g_clear_error (&error);
1516 goto out;
1517 }
1518
1519 g_variant_get (value, "(h)", &index);
1520 g_assert (index >= 0 && index < g_unix_fd_list_get_length (fd_list));
1521
1522 ret = g_new0 (UDisksInhibitCookie, 1);
1523 ret->magic = 0xdeadbeef;
1524 ret->fd = g_unix_fd_list_get (fd_list, index, &error);
1525 if (ret->fd == -1)
1526 {
1527 udisks_critical ("Error getting fd: %s (%s, %d)",
1528 error->message, g_quark_to_string (error->domain), error->code);
1529 g_clear_error (&error);
1530 g_free (ret);
1531 ret = NULL;
1532 goto out;
1533 }
1534
1535 out:
1536 if (value != NULL)
1537 g_variant_unref (value);
1538 g_clear_object (&fd_list);
1539 g_clear_object (&connection);
1540 return ret;
1541 #else
1542 /* non-systemd: just return a dummy pointer */
1543 g_return_val_if_fail (reason != NULL, NULL);
1544 return (UDisksInhibitCookie* ) &udisks_daemon_util_inhibit_system_sync;
1545 #endif
1546 }
1547
1548 /**
1549 * udisks_daemon_util_uninhibit_system_sync:
1550 * @cookie: %NULL or a cookie obtained from udisks_daemon_util_inhibit_system_sync().
1551 *
1552 * Does nothing if @cookie is %NULL, otherwise uninhibits.
1553 */
1554 void
udisks_daemon_util_uninhibit_system_sync(UDisksInhibitCookie * cookie)1555 udisks_daemon_util_uninhibit_system_sync (UDisksInhibitCookie *cookie)
1556 {
1557 #ifdef HAVE_LIBSYSTEMD_LOGIN
1558 if (cookie != NULL)
1559 {
1560 g_assert (cookie->magic == 0xdeadbeef);
1561 if (close (cookie->fd) != 0)
1562 {
1563 udisks_critical ("Error closing inhibit-fd: %m");
1564 }
1565 g_free (cookie);
1566 }
1567 #else
1568 /* non-systemd: check dummy pointer */
1569 g_warn_if_fail (cookie == (UDisksInhibitCookie* ) &udisks_daemon_util_inhibit_system_sync);
1570 #endif
1571 }
1572
1573 /**
1574 * udisks_daemon_util_get_free_mdraid_device:
1575 *
1576 * Gets a free MD RAID device.
1577 *
1578 * Returns: A string of the form "/dev/mdNNN" that should be freed
1579 * with g_free() or %NULL if no free device is available.
1580 */
1581 gchar *
udisks_daemon_util_get_free_mdraid_device(void)1582 udisks_daemon_util_get_free_mdraid_device (void)
1583 {
1584 gchar *ret = NULL;
1585 gint n;
1586 gchar buf[PATH_MAX];
1587
1588 /* Ideally we wouldn't need this racy function... but mdadm(8)
1589 * insists that the user chooses a name. It should just choose one
1590 * itself but that's not how things work right now.
1591 */
1592 for (n = 127; n >= 0; n--)
1593 {
1594 snprintf (buf, sizeof buf, "/sys/block/md%d", n);
1595 if (!g_file_test (buf, G_FILE_TEST_EXISTS))
1596 {
1597 ret = g_strdup_printf ("/dev/md%d", n);
1598 goto out;
1599 }
1600 }
1601
1602 out:
1603 return ret;
1604 }
1605
1606
1607 /**
1608 * udisks_ata_identify_get_word:
1609 * @identify_data: (allow-none): A 512-byte array containing ATA IDENTIFY or ATA IDENTIFY PACKET DEVICE data or %NULL.
1610 * @word_number: The word number to get - must be less than 256.
1611 *
1612 * Gets a <quote>word</quote> from position @word_number from
1613 * @identify_data.
1614 *
1615 * Returns: The word at the specified position or 0 if @identify_data is %NULL.
1616 */
1617 guint16
udisks_ata_identify_get_word(const guchar * identify_data,guint word_number)1618 udisks_ata_identify_get_word (const guchar *identify_data, guint word_number)
1619 {
1620 const guint16 *words = (const guint16 *) identify_data;
1621 guint16 ret = 0;
1622
1623 g_return_val_if_fail (word_number < 256, 0);
1624
1625 if (identify_data == NULL)
1626 goto out;
1627
1628 ret = GUINT16_FROM_LE (words[word_number]);
1629
1630 out:
1631 return ret;
1632 }
1633
1634
1635 /* ---------------------------------------------------------------------------------------------------- */
1636
1637 static volatile guint uevent_serial = 0;
1638
1639 static gboolean
trigger_uevent(const gchar * path,const gchar * str)1640 trigger_uevent (const gchar *path, const gchar *str)
1641 {
1642 gint fd;
1643
1644 fd = open (path, O_WRONLY);
1645 if (fd < 0)
1646 {
1647 udisks_warning ("Error opening %s while triggering uevent: %m", path);
1648 return FALSE;
1649 }
1650
1651 if (write (fd, str, strlen (str)) != (ssize_t) strlen (str))
1652 {
1653 udisks_warning ("Error writing '%s' to file %s: %m", str, path);
1654 close (fd);
1655 return FALSE;
1656 }
1657
1658 close (fd);
1659 return TRUE;
1660 }
1661
1662 typedef struct
1663 {
1664 UDisksDaemon *daemon;
1665 GMainLoop *main_loop;
1666 guint serial;
1667 gchar *uevent_path;
1668 gboolean success;
1669 } SynthUeventData;
1670
1671 static gboolean
trigger_uevent_idle_cb(gpointer user_data)1672 trigger_uevent_idle_cb (gpointer user_data)
1673 {
1674 SynthUeventData *data = user_data;
1675 gchar *str;
1676
1677 str = g_strdup_printf ("change %s UDISKSSERIAL=%u", udisks_daemon_get_uuid (data->daemon), data->serial);
1678
1679 if (! trigger_uevent (data->uevent_path, str))
1680 {
1681 /* kernel refused our string, try simple "change" but don't wait for it */
1682 trigger_uevent (data->uevent_path, "change");
1683 data->success = FALSE;
1684 g_main_loop_quit (data->main_loop);
1685 }
1686 g_free (str);
1687
1688 /* remove the source */
1689 return FALSE;
1690 }
1691
1692 static gboolean
uevent_wait_timeout_cb(gpointer user_data)1693 uevent_wait_timeout_cb (gpointer user_data)
1694 {
1695 SynthUeventData *data = user_data;
1696
1697 data->success = FALSE;
1698 g_main_loop_quit (data->main_loop);
1699
1700 /* remove the source */
1701 return FALSE;
1702 }
1703
1704 static void
uevent_probed_cb(UDisksLinuxProvider * provider,const gchar * action,UDisksLinuxDevice * device,gpointer user_data)1705 uevent_probed_cb (UDisksLinuxProvider *provider,
1706 const gchar *action,
1707 UDisksLinuxDevice *device,
1708 gpointer user_data)
1709 {
1710 SynthUeventData *data = user_data;
1711 const gchar *received_serial_str;
1712 gint64 received_serial;
1713 gchar *endptr;
1714
1715 received_serial_str = g_udev_device_get_property (device->udev_device, "SYNTH_ARG_UDISKSSERIAL");
1716 if (received_serial_str != NULL)
1717 {
1718 endptr = (gchar *) received_serial_str;
1719 received_serial = g_ascii_strtoll (received_serial_str, &endptr, 0);
1720 if (endptr != received_serial_str && received_serial == data->serial)
1721 {
1722 data->success = TRUE;
1723 g_main_loop_quit (data->main_loop);
1724 }
1725 }
1726 }
1727
1728 static gchar *
resolve_uevent_path(UDisksDaemon * daemon,const gchar * device_file,const gchar * sysfs_path)1729 resolve_uevent_path (UDisksDaemon *daemon,
1730 const gchar *device_file,
1731 const gchar *sysfs_path)
1732 {
1733 GUdevClient *gudev_client;
1734 GUdevDevice *gudev_device;
1735 gchar *path = NULL;
1736 gchar *basename;
1737
1738 if (sysfs_path != NULL)
1739 return g_build_filename (sysfs_path, "uevent", NULL);
1740
1741 /* try querying the udev database */
1742 gudev_client = udisks_linux_provider_get_udev_client (udisks_daemon_get_linux_provider (daemon));
1743 /* gudev calls stat() on the device_file, effectively resolving symlinks */
1744 gudev_device = g_udev_client_query_by_device_file (gudev_client, device_file);
1745 if (gudev_device != NULL)
1746 {
1747 path = g_build_filename (g_udev_device_get_sysfs_path (gudev_device), "uevent", NULL);
1748 g_object_unref (gudev_device);
1749 }
1750
1751 if (path != NULL)
1752 return path;
1753
1754 /* construct the path manually, assuming no entries in /dev */
1755 basename = g_path_get_basename (device_file);
1756 path = g_build_filename ("/sys/block", basename, "uevent", NULL);
1757 g_free (basename);
1758
1759 return path;
1760 }
1761
1762 /**
1763 * udisks_daemon_util_trigger_uevent:
1764 * @daemon: A #UDisksDaemon.
1765 * @device_file: Block device file (/dev/xxx) or %NULL.
1766 * @sysfs_path: Device path in /sys or %NULL.
1767 *
1768 * Triggers a 'change' uevent in the kernel.
1769 *
1770 * The @sysfs_path takes precedence if non-NULL over a @device_file.
1771 * In case of using @device_file any symlinks are resolved, this expects
1772 * the block device has been processed by udev already.
1773 *
1774 * The triggered event will bubble up from the kernel through the udev
1775 * stack and will eventually be received by the udisks daemon process
1776 * itself. This method does not wait for the event to be received.
1777 */
1778 void
udisks_daemon_util_trigger_uevent(UDisksDaemon * daemon,const gchar * device_file,const gchar * sysfs_path)1779 udisks_daemon_util_trigger_uevent (UDisksDaemon *daemon,
1780 const gchar *device_file,
1781 const gchar *sysfs_path)
1782 {
1783 gchar *path;
1784
1785 g_return_if_fail (UDISKS_IS_DAEMON (daemon));
1786 g_return_if_fail (device_file != NULL || sysfs_path != NULL);
1787
1788 path = resolve_uevent_path (daemon, device_file, sysfs_path);
1789 trigger_uevent (path, "change");
1790 g_free (path);
1791 }
1792
1793 /**
1794 * udisks_daemon_util_trigger_uevent_sync:
1795 * @daemon: A #UDisksDaemon.
1796 * @device_file: Block device file (/dev/xxx) or %NULL.
1797 * @sysfs_path: Device path in /sys or %NULL.
1798 * @timeout_seconds: Maximum time to wait for the uevent (in seconds).
1799 *
1800 * Triggers a 'change' uevent in the kernel and waits until it's received and
1801 * processed by udisks.
1802 *
1803 * The @sysfs_path takes precedence if non-NULL over a @device_file.
1804 * In case of using @device_file any symlinks are resolved, this expects
1805 * the block device has been processed by udev already.
1806 *
1807 * Unlike udisks_daemon_util_trigger_uevent() that just triggers
1808 * a synthetic uevent to the kernel, this call will actually block and wait until
1809 * the #UDisksLinuxProvider receives the uevent, performs probing and processes
1810 * the uevent further down the UDisks object stack. Upon returning from this
1811 * function call the caller may assume the event has been fully processed, all
1812 * D-Bus objects are updated and settled. Typically used in busy wait for
1813 * a particular D-Bus interface.
1814 *
1815 * Note that this uses synthetic uevent tagging and only works on linux kernel
1816 * 4.13 and higher. In case an older kernel is detected this acts like the classic
1817 * udisks_daemon_util_trigger_uevent() call and %FALSE is returned.
1818 *
1819 * Returns: %TRUE if the uevent has been successfully received, %FALSE otherwise
1820 * or when the kernel version is too old.
1821 */
1822 gboolean
udisks_daemon_util_trigger_uevent_sync(UDisksDaemon * daemon,const gchar * device_file,const gchar * sysfs_path,guint timeout_seconds)1823 udisks_daemon_util_trigger_uevent_sync (UDisksDaemon *daemon,
1824 const gchar *device_file,
1825 const gchar *sysfs_path,
1826 guint timeout_seconds)
1827 {
1828 UDisksLinuxProvider *provider;
1829 SynthUeventData data;
1830 GMainContext *main_context;
1831 GSource *idle_source;
1832 GSource *timeout_source;
1833
1834 g_return_val_if_fail (UDISKS_IS_DAEMON (daemon), FALSE);
1835 g_return_val_if_fail (device_file != NULL || sysfs_path != NULL, FALSE);
1836
1837 if (bd_utils_check_linux_version (4, 13, 0) < 0)
1838 {
1839 udisks_daemon_util_trigger_uevent (daemon, device_file, sysfs_path);
1840 return FALSE;
1841 }
1842
1843 data.daemon = daemon;
1844 data.uevent_path = resolve_uevent_path (daemon, device_file, sysfs_path);
1845 if (data.uevent_path == NULL)
1846 return FALSE;
1847 data.serial = g_atomic_int_add (&uevent_serial, 1);
1848
1849 main_context = g_main_context_new ();
1850 g_main_context_push_thread_default (main_context);
1851 data.main_loop = g_main_loop_new (main_context, FALSE);
1852
1853 /* queue the actual trigger in the loop */
1854 idle_source = g_idle_source_new ();
1855 g_source_set_callback (idle_source, (GSourceFunc) trigger_uevent_idle_cb, &data, NULL);
1856 g_source_attach (idle_source, main_context);
1857 g_source_unref (idle_source);
1858
1859 /* add timeout as a fallback */
1860 timeout_source = g_timeout_source_new_seconds (timeout_seconds);
1861 g_source_set_callback (timeout_source, (GSourceFunc) uevent_wait_timeout_cb, &data, NULL);
1862 g_source_attach (timeout_source, main_context);
1863 g_source_unref (timeout_source);
1864
1865 /* catch incoming uevents */
1866 provider = udisks_daemon_get_linux_provider (daemon);
1867 g_signal_connect (provider, "uevent-probed", G_CALLBACK (uevent_probed_cb), &data);
1868
1869 data.success = FALSE;
1870 g_main_loop_run (data.main_loop);
1871
1872 g_signal_handlers_disconnect_by_func (provider, uevent_probed_cb, &data);
1873 g_main_context_pop_thread_default (main_context);
1874
1875 g_main_loop_unref (data.main_loop);
1876 g_main_context_unref (main_context);
1877 g_free (data.uevent_path);
1878
1879 return data.success;
1880 }
1881
1882 /* ---------------------------------------------------------------------------------------------------- */
1883