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