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 #define _GNU_SOURCE /* for O_DIRECT */
22
23 #include "config.h"
24 #include <glib/gi18n-lib.h>
25
26 #include <sys/types.h>
27 #include <sys/mount.h>
28 #include <sys/stat.h>
29 #include <fcntl.h>
30 #include <pwd.h>
31 #include <grp.h>
32 #include <string.h>
33 #include <stdlib.h>
34 #include <errno.h>
35 #include <mntent.h>
36
37 #include <glib/gstdio.h>
38 #include <gio/gunixfdlist.h>
39
40 #include <libmount/libmount.h>
41
42 #include <blockdev/part.h>
43 #include <blockdev/fs.h>
44 #include <blockdev/crypto.h>
45
46 #include "udiskslogging.h"
47 #include "udiskslinuxblock.h"
48 #include "udiskslinuxblockobject.h"
49 #include "udiskslinuxdriveobject.h"
50 #include "udiskslinuxfsinfo.h"
51 #include "udisksdaemon.h"
52 #include "udisksstate.h"
53 #include "udisksprivate.h"
54 #include "udisksconfigmanager.h"
55 #include "udisksdaemonutil.h"
56 #include "udiskslinuxprovider.h"
57 #include "udisksfstabentry.h"
58 #include "udiskscrypttabmonitor.h"
59 #include "udiskscrypttabentry.h"
60 #include "udisksdaemonutil.h"
61 #include "udisksbasejob.h"
62 #include "udiskssimplejob.h"
63 #include "udiskslinuxdriveata.h"
64 #include "udiskslinuxmdraidobject.h"
65 #include "udiskslinuxdevice.h"
66 #include "udiskslinuxpartition.h"
67 #include "udiskslinuxencrypted.h"
68 #include "udiskslinuxencryptedhelpers.h"
69 #include "udiskslinuxpartitiontable.h"
70 #include "udiskslinuxfilesystemhelpers.h"
71
72 #ifdef HAVE_LIBMOUNT_UTAB
73 #include "udisksutabmonitor.h"
74 #include "udisksutabentry.h"
75 #endif
76
77 /**
78 * SECTION:udiskslinuxblock
79 * @title: UDisksLinuxBlock
80 * @short_description: Linux implementation of #UDisksBlock
81 *
82 * This type provides an implementation of the #UDisksBlock
83 * interface on Linux.
84 */
85
86 typedef struct _UDisksLinuxBlockClass UDisksLinuxBlockClass;
87
88 /**
89 * UDisksLinuxBlock:
90 *
91 * The #UDisksLinuxBlock structure contains only private data and should
92 * only be accessed using the provided API.
93 */
94 struct _UDisksLinuxBlock
95 {
96 UDisksBlockSkeleton parent_instance;
97
98 /* only allow single cryptsetup call at once */
99 GMutex encrypted_lock;
100 };
101
102 struct _UDisksLinuxBlockClass
103 {
104 UDisksBlockSkeletonClass parent_class;
105 };
106
107 static void block_iface_init (UDisksBlockIface *iface);
108
109 G_DEFINE_TYPE_WITH_CODE (UDisksLinuxBlock, udisks_linux_block, UDISKS_TYPE_BLOCK_SKELETON,
110 G_IMPLEMENT_INTERFACE (UDISKS_TYPE_BLOCK, block_iface_init));
111
112 /* ---------------------------------------------------------------------------------------------------- */
113
114 static void
udisks_linux_block_init(UDisksLinuxBlock * block)115 udisks_linux_block_init (UDisksLinuxBlock *block)
116 {
117 g_mutex_init (&(block->encrypted_lock));
118 g_dbus_interface_skeleton_set_flags (G_DBUS_INTERFACE_SKELETON (block),
119 G_DBUS_INTERFACE_SKELETON_FLAGS_HANDLE_METHOD_INVOCATIONS_IN_THREAD);
120 }
121
122 static void
udisks_linux_block_finalize(GObject * object)123 udisks_linux_block_finalize (GObject *object)
124 {
125 UDisksLinuxBlock *block = UDISKS_LINUX_BLOCK (object);
126
127 g_mutex_clear (&(block->encrypted_lock));
128
129 if (G_OBJECT_CLASS (udisks_linux_block_parent_class)->finalize != NULL)
130 G_OBJECT_CLASS (udisks_linux_block_parent_class)->finalize (object);
131 }
132
133 static void
udisks_linux_block_class_init(UDisksLinuxBlockClass * klass)134 udisks_linux_block_class_init (UDisksLinuxBlockClass *klass)
135 {
136 GObjectClass *gobject_class;
137
138 gobject_class = G_OBJECT_CLASS (klass);
139 gobject_class->finalize = udisks_linux_block_finalize;
140 }
141
142 /**
143 * udisks_linux_block_new:
144 *
145 * Creates a new #UDisksLinuxBlock instance.
146 *
147 * Returns: A new #UDisksLinuxBlock. Free with g_object_unref().
148 */
149 UDisksBlock *
udisks_linux_block_new(void)150 udisks_linux_block_new (void)
151 {
152 return UDISKS_BLOCK (g_object_new (UDISKS_TYPE_LINUX_BLOCK,
153 NULL));
154 }
155
156 /* ---------------------------------------------------------------------------------------------------- */
157
158 static gchar *
get_sysfs_attr(GUdevDevice * device,const gchar * attr)159 get_sysfs_attr (GUdevDevice *device,
160 const gchar *attr)
161 {
162 gchar *filename = NULL;
163 gchar *value = NULL;
164 gboolean ret = FALSE;
165 GError *error = NULL;
166
167 filename = g_strconcat (g_udev_device_get_sysfs_path (device),
168 "/",
169 attr,
170 NULL);
171
172
173 ret = g_file_get_contents (filename,
174 &value,
175 NULL,
176 &error);
177 if (!ret)
178 {
179 udisks_debug ("Failed to read sysfs attribute %s: %s", attr, error->message);
180 g_clear_error (&error);
181 }
182
183 g_free (filename);
184 return value;
185 }
186
187 /* ---------------------------------------------------------------------------------------------------- */
188
189 static UDisksLinuxBlockObject *
find_block_device_by_sysfs_path(GDBusObjectManagerServer * object_manager,const gchar * sysfs_path)190 find_block_device_by_sysfs_path (GDBusObjectManagerServer *object_manager,
191 const gchar *sysfs_path)
192 {
193 UDisksLinuxBlockObject *ret;
194 GList *objects;
195 GList *l;
196
197 ret = NULL;
198
199 objects = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (object_manager));
200 for (l = objects; l != NULL; l = l->next)
201 {
202 GDBusObjectSkeleton *object = G_DBUS_OBJECT_SKELETON (l->data);
203 UDisksLinuxDevice *device;
204
205 if (!UDISKS_IS_LINUX_BLOCK_OBJECT (object))
206 continue;
207
208 device = udisks_linux_block_object_get_device (UDISKS_LINUX_BLOCK_OBJECT (object));
209 if (g_strcmp0 (sysfs_path, g_udev_device_get_sysfs_path (device->udev_device)) == 0)
210 {
211 ret = g_object_ref (UDISKS_LINUX_BLOCK_OBJECT (object));
212 g_object_unref (device);
213 goto out;
214 }
215 g_object_unref (device);
216 }
217
218 out:
219 g_list_free_full (objects, g_object_unref);
220 return ret;
221 }
222
223 /* ---------------------------------------------------------------------------------------------------- */
224
225 static gchar *
find_drive(GDBusObjectManagerServer * object_manager,GUdevDevice * block_device,UDisksDrive ** out_drive)226 find_drive (GDBusObjectManagerServer *object_manager,
227 GUdevDevice *block_device,
228 UDisksDrive **out_drive)
229 {
230 GUdevDevice *whole_disk_block_device;
231 const gchar *whole_disk_block_device_sysfs_path;
232 gchar *ret;
233 GList *objects;
234 GList *l;
235
236 ret = NULL;
237
238 if (g_strcmp0 (g_udev_device_get_devtype (block_device), "disk") == 0)
239 whole_disk_block_device = g_object_ref (block_device);
240 else
241 whole_disk_block_device = g_udev_device_get_parent_with_subsystem (block_device, "block", "disk");
242 whole_disk_block_device_sysfs_path = g_udev_device_get_sysfs_path (whole_disk_block_device);
243
244 objects = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (object_manager));
245 for (l = objects; l != NULL; l = l->next)
246 {
247 GDBusObjectSkeleton *object = G_DBUS_OBJECT_SKELETON (l->data);
248 GList *drive_devices;
249 GList *j;
250
251 if (!UDISKS_IS_LINUX_DRIVE_OBJECT (object))
252 continue;
253
254 drive_devices = udisks_linux_drive_object_get_devices (UDISKS_LINUX_DRIVE_OBJECT (object));
255 for (j = drive_devices; j != NULL; j = j->next)
256 {
257 UDisksLinuxDevice *drive_device = UDISKS_LINUX_DEVICE (j->data);
258 const gchar *drive_sysfs_path;
259
260 drive_sysfs_path = g_udev_device_get_sysfs_path (drive_device->udev_device);
261 if (g_strcmp0 (whole_disk_block_device_sysfs_path, drive_sysfs_path) == 0)
262 {
263 if (out_drive != NULL)
264 *out_drive = udisks_object_get_drive (UDISKS_OBJECT (object));
265 ret = g_strdup (g_dbus_object_get_object_path (G_DBUS_OBJECT (object)));
266 g_list_free_full (drive_devices, g_object_unref);
267 goto out;
268 }
269 }
270 g_list_free_full (drive_devices, g_object_unref);
271 }
272
273 out:
274 g_list_free_full (objects, g_object_unref);
275 g_object_unref (whole_disk_block_device);
276 return ret;
277 }
278
279 /* ---------------------------------------------------------------------------------------------------- */
280
281 static UDisksLinuxMDRaidObject *
find_mdraid(GDBusObjectManagerServer * object_manager,const gchar * md_uuid)282 find_mdraid (GDBusObjectManagerServer *object_manager,
283 const gchar *md_uuid)
284 {
285 UDisksLinuxMDRaidObject *ret = NULL;
286 GList *objects = NULL, *l;
287
288 objects = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (object_manager));
289 for (l = objects; l != NULL; l = l->next)
290 {
291 GDBusObjectSkeleton *object = G_DBUS_OBJECT_SKELETON (l->data);
292 if (UDISKS_IS_LINUX_MDRAID_OBJECT (object))
293 {
294 UDisksMDRaid *mdraid = udisks_object_get_mdraid (UDISKS_OBJECT (object));
295 if (mdraid != NULL)
296 {
297 if (g_strcmp0 (udisks_mdraid_get_uuid (mdraid), md_uuid) == 0)
298 {
299 ret = UDISKS_LINUX_MDRAID_OBJECT (g_object_ref (object));
300 g_object_unref (mdraid);
301 goto out;
302 }
303 g_object_unref (mdraid);
304 }
305 }
306 }
307
308 out:
309 g_list_free_full (objects, g_object_unref);
310 return ret;
311 }
312
313 /* ---------------------------------------------------------------------------------------------------- */
314
315 static void
update_mdraid(UDisksLinuxBlock * block,UDisksLinuxDevice * device,UDisksDrive * drive,GDBusObjectManagerServer * object_manager)316 update_mdraid (UDisksLinuxBlock *block,
317 UDisksLinuxDevice *device,
318 UDisksDrive *drive,
319 GDBusObjectManagerServer *object_manager)
320 {
321 UDisksBlock *iface = UDISKS_BLOCK (block);
322 const gchar *uuid;
323 const gchar *objpath_mdraid = "/";
324 const gchar *objpath_mdraid_member = "/";
325 UDisksLinuxMDRaidObject *object = NULL;
326
327 uuid = g_udev_device_get_property (device->udev_device, "UDISKS_MD_UUID");
328 if (uuid != NULL && strlen (uuid) > 0)
329 {
330 object = find_mdraid (object_manager, uuid);
331 if (object != NULL)
332 {
333 objpath_mdraid = g_dbus_object_get_object_path (G_DBUS_OBJECT (object));
334 g_clear_object (&object);
335 }
336 }
337
338 uuid = g_udev_device_get_property (device->udev_device, "UDISKS_MD_MEMBER_UUID");
339 if (uuid != NULL && strlen (uuid) > 0)
340 {
341 object = find_mdraid (object_manager, uuid);
342 if (object != NULL)
343 {
344 objpath_mdraid_member = g_dbus_object_get_object_path (G_DBUS_OBJECT (object));
345 g_clear_object (&object);
346 }
347 }
348
349 udisks_block_set_mdraid (iface, objpath_mdraid);
350 udisks_block_set_mdraid_member (iface, objpath_mdraid_member);
351 }
352
353 /* ---------------------------------------------------------------------------------------------------- */
354
355 /**
356 * udisks_linux_block_matches_id:
357 * @block: A #UDisksLinuxBlock.
358 * @device_path: A device path string.
359 *
360 * Compares block device identifiers and returns %TRUE if match is found. The @device_path
361 * argument may be a device file or a common KEY=VALUE identifier as used e.g. in /etc/fstab
362 * or /etc/crypttab.
363 *
364 * Returns: %TRUE when identifiers do match, %FALSE otherwise.
365 */
366 gboolean
udisks_linux_block_matches_id(UDisksLinuxBlock * block,const gchar * device_path)367 udisks_linux_block_matches_id (UDisksLinuxBlock *block,
368 const gchar *device_path)
369 {
370 const gchar *device = NULL;
371 const gchar *label = NULL;
372 const gchar *uuid = NULL;
373 const gchar *partuuid = NULL;
374 const gchar *partlabel = NULL;
375 const gchar *const *symlinks;
376
377 if (device_path == NULL || strlen (device_path) < 1)
378 {
379 return FALSE;
380 }
381 if (g_str_has_prefix (device_path, "UUID="))
382 {
383 uuid = device_path + 5;
384 }
385 else if (g_str_has_prefix (device_path, "LABEL="))
386 {
387 label = device_path + 6;
388 }
389 else if (g_str_has_prefix (device_path, "PARTUUID="))
390 {
391 partuuid = device_path + 9;
392 }
393 else if (g_str_has_prefix (device_path, "PARTLABEL="))
394 {
395 partlabel = device_path + 10;
396 }
397 else if (g_str_has_prefix (device_path, "/dev"))
398 {
399 device = device_path;
400 }
401 else
402 {
403 /* ignore non-device entry */
404 return FALSE;
405 }
406
407 if (device != NULL)
408 {
409 if (g_strcmp0 (device, udisks_block_get_device (UDISKS_BLOCK (block))) == 0)
410 return TRUE;
411
412 symlinks = udisks_block_get_symlinks (UDISKS_BLOCK (block));
413 if (symlinks && g_strv_contains (symlinks, device))
414 return TRUE;
415 }
416 if (label != NULL && g_strcmp0 (label, udisks_block_get_id_label (UDISKS_BLOCK (block))) == 0)
417 {
418 return TRUE;
419 }
420 if (uuid != NULL && g_strcmp0 (uuid, udisks_block_get_id_uuid (UDISKS_BLOCK (block))) == 0)
421 {
422 return TRUE;
423 }
424 if (partlabel != NULL || partuuid != NULL)
425 {
426 UDisksLinuxBlockObject *object;
427 UDisksLinuxDevice *linux_device;
428
429 object = udisks_daemon_util_dup_object (block, NULL);
430 if (object != NULL)
431 {
432 linux_device = udisks_linux_block_object_get_device (object);
433 g_clear_object (&object);
434 if (linux_device != NULL && linux_device->udev_device != NULL &&
435 ((partuuid != NULL && g_strcmp0 (partuuid, g_udev_device_get_property (linux_device->udev_device, "ID_PART_ENTRY_UUID")) == 0) ||
436 (partlabel != NULL && g_strcmp0 (partlabel, g_udev_device_get_property (linux_device->udev_device, "ID_PART_ENTRY_NAME")) == 0)))
437 {
438 g_object_unref (linux_device);
439 return TRUE;
440 }
441 g_clear_object (&linux_device);
442 }
443 }
444
445 return FALSE;
446 }
447
448 static GList *
find_fstab_entries(UDisksDaemon * daemon,UDisksLinuxBlock * block,const gchar * needle)449 find_fstab_entries (UDisksDaemon *daemon,
450 UDisksLinuxBlock *block,
451 const gchar *needle)
452 {
453 struct libmnt_table *table;
454 struct libmnt_iter* iter;
455 struct libmnt_fs *fs = NULL;
456 GList *ret = NULL;
457
458 table = mnt_new_table ();
459 if (mnt_table_parse_fstab (table, NULL) < 0)
460 {
461 mnt_free_table (table);
462 return NULL;
463 }
464
465 iter = mnt_new_iter (MNT_ITER_FORWARD);
466 while (mnt_table_next_fs (table, iter, &fs) == 0)
467 {
468 UDisksFstabEntry *entry;
469
470 if (block != NULL)
471 {
472 if (! udisks_linux_block_matches_id (block, mnt_fs_get_source (fs)))
473 continue;
474 }
475 else if (needle != NULL)
476 {
477 const char *opts;
478
479 opts = mnt_fs_get_options (fs);
480 if (! opts || g_strstr_len (opts, -1, needle) == NULL)
481 continue;
482 }
483
484 entry = _udisks_fstab_entry_new_from_mnt_fs (fs);
485 ret = g_list_prepend (ret, entry);
486 }
487 mnt_free_iter (iter);
488 mnt_free_table (table);
489
490 return g_list_reverse (ret);
491 }
492
493 static GList *
find_crypttab_entries_for_device(UDisksLinuxBlock * block,UDisksDaemon * daemon)494 find_crypttab_entries_for_device (UDisksLinuxBlock *block,
495 UDisksDaemon *daemon)
496 {
497 GList *entries;
498 GList *l;
499 GList *ret;
500
501 ret = NULL;
502
503 /* if this is too slow, we could add lookup methods to UDisksCrypttabMonitor... */
504 entries = udisks_crypttab_monitor_get_entries (udisks_daemon_get_crypttab_monitor (daemon));
505 for (l = entries; l != NULL; l = l->next)
506 {
507 UDisksCrypttabEntry *entry = UDISKS_CRYPTTAB_ENTRY (l->data);
508 const gchar *device;
509
510 device = udisks_crypttab_entry_get_device (entry);
511 if (udisks_linux_block_matches_id (block, device))
512 ret = g_list_prepend (ret, g_object_ref (entry));
513 }
514
515 g_list_free_full (entries, g_object_unref);
516 return ret;
517 }
518
519 static GList *
find_crypttab_entries_for_needle(gchar * needle,UDisksDaemon * daemon)520 find_crypttab_entries_for_needle (gchar *needle,
521 UDisksDaemon *daemon)
522 {
523 GList *entries;
524 GList *l;
525 GList *ret;
526
527 ret = NULL;
528
529 entries = udisks_crypttab_monitor_get_entries (udisks_daemon_get_crypttab_monitor (daemon));
530 for (l = entries; l != NULL; l = l->next)
531 {
532 UDisksCrypttabEntry *entry = UDISKS_CRYPTTAB_ENTRY (l->data);
533 const gchar *opts = NULL;
534
535 opts = udisks_crypttab_entry_get_options (entry);
536 if (opts && strstr(opts, needle))
537 ret = g_list_prepend (ret, g_object_ref (entry));
538 }
539
540 g_list_free_full (entries, g_object_unref);
541 return ret;
542 }
543
544 #ifdef HAVE_LIBMOUNT_UTAB
545 static GList *
find_utab_entries_for_device(UDisksLinuxBlock * block,UDisksDaemon * daemon)546 find_utab_entries_for_device (UDisksLinuxBlock *block,
547 UDisksDaemon *daemon)
548 {
549 GSList *entries, *l;
550 GList *ret;
551
552 ret = NULL;
553
554 /* if this is too slow, we could add lookup methods to UDisksUtabMonitor... */
555 entries = udisks_utab_monitor_get_entries (udisks_daemon_get_utab_monitor (daemon));
556 for (l = entries; l != NULL; l = l->next)
557 {
558 UDisksUtabEntry *entry = UDISKS_UTAB_ENTRY (l->data);
559 const gchar *source = udisks_utab_entry_get_source (entry);
560
561 if (!g_str_has_prefix (source, "/dev"))
562 continue;
563
564 if (udisks_linux_block_matches_id (block, source))
565 ret = g_list_prepend (ret, g_object_ref (entry));
566 }
567
568 g_slist_free_full (entries, g_object_unref);
569 return ret;
570 }
571 #endif
572
573 static void
add_fstab_entry(GVariantBuilder * builder,UDisksFstabEntry * entry)574 add_fstab_entry (GVariantBuilder *builder,
575 UDisksFstabEntry *entry)
576 {
577 GVariantBuilder dict_builder;
578 g_variant_builder_init (&dict_builder, G_VARIANT_TYPE_VARDICT);
579 g_variant_builder_add (&dict_builder, "{sv}", "fsname",
580 g_variant_new_bytestring (udisks_fstab_entry_get_fsname (entry)));
581 g_variant_builder_add (&dict_builder, "{sv}", "dir",
582 g_variant_new_bytestring (udisks_fstab_entry_get_dir (entry)));
583 g_variant_builder_add (&dict_builder, "{sv}", "type",
584 g_variant_new_bytestring (udisks_fstab_entry_get_fstype (entry)));
585 g_variant_builder_add (&dict_builder, "{sv}", "opts",
586 g_variant_new_bytestring (udisks_fstab_entry_get_opts (entry)));
587 g_variant_builder_add (&dict_builder, "{sv}", "freq",
588 g_variant_new_int32 (udisks_fstab_entry_get_freq (entry)));
589 g_variant_builder_add (&dict_builder, "{sv}", "passno",
590 g_variant_new_int32 (udisks_fstab_entry_get_passno (entry)));
591 g_variant_builder_add (builder,
592 "(sa{sv})",
593 "fstab", &dict_builder);
594 }
595
596 static gboolean
add_crypttab_entry(GVariantBuilder * builder,UDisksCrypttabEntry * entry,gboolean include_secrets,GError ** error)597 add_crypttab_entry (GVariantBuilder *builder,
598 UDisksCrypttabEntry *entry,
599 gboolean include_secrets,
600 GError **error)
601 {
602 GVariantBuilder dict_builder;
603 const gchar *passphrase_path;
604 const gchar *options;
605 gchar *passphrase_contents;
606 gsize passphrase_contents_length;
607
608 passphrase_path = udisks_crypttab_entry_get_passphrase_path (entry);
609 if (passphrase_path == NULL || g_strcmp0 (passphrase_path, "none") == 0)
610 passphrase_path = "";
611 passphrase_contents = NULL;
612 if (!(g_strcmp0 (passphrase_path, "") == 0 || g_str_has_prefix (passphrase_path, "/dev")))
613 {
614 if (include_secrets)
615 {
616 if (!g_file_get_contents (passphrase_path,
617 &passphrase_contents,
618 &passphrase_contents_length,
619 error))
620 {
621 g_prefix_error (error,
622 "Error loading secrets from file `%s' referenced in /etc/crypttab entry: ",
623 passphrase_path);
624 return FALSE;
625 }
626 }
627 }
628
629 options = udisks_crypttab_entry_get_options (entry);
630 if (options == NULL)
631 options = "";
632
633 g_variant_builder_init (&dict_builder, G_VARIANT_TYPE_VARDICT);
634 g_variant_builder_add (&dict_builder, "{sv}", "name",
635 g_variant_new_bytestring (udisks_crypttab_entry_get_name (entry)));
636 g_variant_builder_add (&dict_builder, "{sv}", "device",
637 g_variant_new_bytestring (udisks_crypttab_entry_get_device (entry)));
638 g_variant_builder_add (&dict_builder, "{sv}", "passphrase-path",
639 g_variant_new_bytestring (passphrase_path));
640 if (passphrase_contents != NULL)
641 {
642 g_variant_builder_add (&dict_builder, "{sv}", "passphrase-contents",
643 g_variant_new_bytestring (passphrase_contents));
644 }
645 g_variant_builder_add (&dict_builder, "{sv}", "options",
646 g_variant_new_bytestring (options));
647 g_variant_builder_add (builder,
648 "(sa{sv})",
649 "crypttab", &dict_builder);
650 if (passphrase_contents != NULL)
651 {
652 memset (passphrase_contents, '\0', passphrase_contents_length);
653 g_free (passphrase_contents);
654 }
655
656 return TRUE;
657 }
658
659 /* returns a floating GVariant */
660 static GVariant *
calculate_configuration(UDisksLinuxBlock * block,UDisksDaemon * daemon,gboolean include_secrets,GError ** error)661 calculate_configuration (UDisksLinuxBlock *block,
662 UDisksDaemon *daemon,
663 gboolean include_secrets,
664 GError **error)
665 {
666 GList *entries;
667 GList *l;
668 GVariantBuilder builder;
669 GVariant *ret;
670
671 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
672
673 ret = NULL;
674
675 g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(sa{sv})"));
676 /* First the /etc/fstab entries */
677 entries = find_fstab_entries (daemon, block, NULL);
678 for (l = entries; l != NULL; l = l->next)
679 add_fstab_entry (&builder, UDISKS_FSTAB_ENTRY (l->data));
680 g_list_free_full (entries, g_object_unref);
681
682 /* Then the /etc/crypttab entries (currently only supported for LUKS) */
683 if (udisks_linux_block_is_luks (UDISKS_BLOCK (block)))
684 {
685 entries = find_crypttab_entries_for_device (block, daemon);
686 for (l = entries; l != NULL; l = l->next)
687 {
688 if (!add_crypttab_entry (&builder, UDISKS_CRYPTTAB_ENTRY (l->data), include_secrets, error))
689 {
690 g_variant_builder_clear (&builder);
691 g_list_free_full (entries, g_object_unref);
692 goto out;
693 }
694 }
695 g_list_free_full (entries, g_object_unref);
696 }
697
698 ret = g_variant_builder_end (&builder);
699
700 out:
701 return ret;
702 }
703
704 #ifdef HAVE_LIBMOUNT_UTAB
705 static gchar **
calculate_userspace_mount_options(UDisksLinuxBlock * block,UDisksDaemon * daemon)706 calculate_userspace_mount_options (UDisksLinuxBlock *block,
707 UDisksDaemon *daemon)
708 {
709 GList *entries, *l;
710 GPtrArray *ret;
711
712 ret = g_ptr_array_new ();
713
714 /* Get the /run/mounts/utab entries */
715 entries = find_utab_entries_for_device (block, daemon);
716 for (l = entries; l != NULL; l = l->next) {
717 UDisksUtabEntry *entry = UDISKS_UTAB_ENTRY (l->data);
718 const gchar * const *opts = udisks_utab_entry_get_opts (entry);
719 for (gint i = 0; opts[i] != NULL; ++i)
720 g_ptr_array_add (ret, g_strdup (opts[i]));
721 }
722 g_ptr_array_add (ret, NULL);
723 g_list_free_full (entries, g_object_unref);
724
725 return (gchar **) g_ptr_array_free (ret, FALSE);
726 }
727 #endif
728
729 static void
update_configuration(UDisksLinuxBlock * block,UDisksDaemon * daemon)730 update_configuration (UDisksLinuxBlock *block,
731 UDisksDaemon *daemon)
732 {
733 GVariant *configuration;
734 GError *error;
735
736 error = NULL;
737 configuration = calculate_configuration (block, daemon, FALSE, &error);
738 if (configuration == NULL)
739 {
740 udisks_warning ("Error loading configuration: %s (%s, %d)",
741 error->message, g_quark_to_string (error->domain), error->code);
742 g_clear_error (&error);
743 configuration = g_variant_new ("a(sa{sv})", NULL);
744 }
745 udisks_block_set_configuration (UDISKS_BLOCK (block), configuration);
746 g_dbus_interface_skeleton_flush (G_DBUS_INTERFACE_SKELETON (block));
747 }
748
749 #ifdef HAVE_LIBMOUNT_UTAB
750 static void
update_userspace_mount_options(UDisksLinuxBlock * block,UDisksDaemon * daemon)751 update_userspace_mount_options (UDisksLinuxBlock *block,
752 UDisksDaemon *daemon)
753 {
754 gchar **opts;
755
756 opts = calculate_userspace_mount_options (block, daemon);
757 udisks_block_set_userspace_mount_options (UDISKS_BLOCK (block), (const gchar * const*) opts);
758
759 g_strfreev (opts);
760 }
761 #endif
762
763 /* ---------------------------------------------------------------------------------------------------- */
764
765 /* returns a floating GVariant */
766 static GVariant *
find_configurations(gchar * needle,UDisksDaemon * daemon,gboolean include_secrets,GError ** error)767 find_configurations (gchar *needle,
768 UDisksDaemon *daemon,
769 gboolean include_secrets,
770 GError **error)
771 {
772 GList *entries;
773 GList *l;
774 GVariantBuilder builder;
775 GVariant *ret;
776
777 udisks_debug ("Looking for %s", needle);
778
779 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
780
781 ret = NULL;
782
783 g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(sa{sv})"));
784 /* First the /etc/fstab entries */
785 entries = find_fstab_entries (daemon, NULL, needle);
786 for (l = entries; l != NULL; l = l->next)
787 add_fstab_entry (&builder, UDISKS_FSTAB_ENTRY (l->data));
788 g_list_free_full (entries, g_object_unref);
789
790 /* Then the /etc/crypttab entries */
791 entries = find_crypttab_entries_for_needle (needle, daemon);
792 for (l = entries; l != NULL; l = l->next)
793 {
794 if (!add_crypttab_entry (&builder, UDISKS_CRYPTTAB_ENTRY (l->data), include_secrets, error))
795 {
796 g_variant_builder_clear (&builder);
797 g_list_free_full (entries, g_object_unref);
798 goto out;
799 }
800 }
801 g_list_free_full (entries, g_object_unref);
802
803 ret = g_variant_builder_end (&builder);
804
805 out:
806 return ret;
807 }
808
809 GVariant *
udisks_linux_find_child_configuration(UDisksDaemon * daemon,const gchar * uuid)810 udisks_linux_find_child_configuration (UDisksDaemon *daemon,
811 const gchar *uuid)
812 {
813 GError *error = NULL;
814 gchar *needle = g_strdup_printf ("x-parent=%s", uuid);
815 GVariant *res = find_configurations (needle, daemon, FALSE, &error);
816 if (res == NULL)
817 {
818 udisks_warning ("Error loading configuration: %s (%s, %d)",
819 error->message, g_quark_to_string (error->domain), error->code);
820 g_clear_error (&error);
821 res = g_variant_new ("a(sa{sv})", NULL);
822 }
823 g_free (needle);
824 return res;
825 }
826
827 /* ---------------------------------------------------------------------------------------------------- */
828
829 static void
update_hints(UDisksDaemon * daemon,UDisksLinuxBlock * block,UDisksLinuxDevice * device,UDisksDrive * drive)830 update_hints (UDisksDaemon *daemon,
831 UDisksLinuxBlock *block,
832 UDisksLinuxDevice *device,
833 UDisksDrive *drive)
834 {
835 UDisksBlock *iface = UDISKS_BLOCK (block);
836 gboolean hint_partitionable;
837 gboolean hint_system;
838 gboolean hint_ignore;
839 gboolean hint_auto;
840 const gchar *hint_name;
841 const gchar *hint_icon_name;
842 const gchar *hint_symbolic_icon_name;
843 const gchar *device_file;
844 GList *fstab_entries;
845 GList *l;
846
847 /* very conservative defaults */
848 hint_partitionable = TRUE;
849 hint_system = TRUE;
850 hint_ignore = FALSE;
851 hint_auto = FALSE;
852 hint_name = NULL;
853 hint_icon_name = NULL;
854 hint_symbolic_icon_name = NULL;
855
856 device_file = g_udev_device_get_device_file (device->udev_device);
857
858 /* Provide easy access to _only_ the following devices
859 *
860 * - anything connected via known local buses (e.g. USB or Firewire, MMC or MemoryStick)
861 * - any device with removable media
862 *
863 * Be careful when extending this list as we don't want to automount
864 * the world when (inadvertently) connecting to a SAN.
865 */
866 if (drive != NULL)
867 {
868 const gchar *connection_bus;
869 gboolean removable;
870 connection_bus = udisks_drive_get_connection_bus (drive);
871 removable = udisks_drive_get_media_removable (drive);
872 if (removable ||
873 g_strcmp0 (connection_bus, "usb") == 0 ||
874 g_strcmp0 (connection_bus, "ieee1394") == 0 ||
875 g_str_has_prefix (device_file, "/dev/msblk") ||
876 g_str_has_prefix (device_file, "/dev/mspblk"))
877 {
878 hint_system = FALSE;
879 hint_auto = TRUE;
880 }
881 }
882
883 /* Floppy drives are not partitionable and should never be auto-mounted */
884 if (g_str_has_prefix (device_file, "/dev/fd"))
885 {
886 hint_system = FALSE;
887 hint_partitionable = FALSE;
888 hint_auto = FALSE;
889 }
890
891 /* CD-ROM media / drives are not partitionable, at least not here on Linux */
892 if (g_udev_device_get_property_as_boolean (device->udev_device, "ID_CDROM"))
893 hint_partitionable = FALSE;
894
895 /* device-mapper devices are not partitionable (TODO: for multipath, they are via kpartx(8) hacks) */
896 if (g_str_has_prefix (g_udev_device_get_name (device->udev_device), "dm-"))
897 hint_partitionable = FALSE;
898
899 /* Check fstab entries */
900 fstab_entries = find_fstab_entries (daemon, block, NULL);
901 for (l = fstab_entries; l != NULL; l = l->next)
902 {
903 UDisksFstabEntry *entry = UDISKS_FSTAB_ENTRY (l->data);
904 /* Honour the sysadmin-specified 'noauto' mount option */
905 if (udisks_fstab_entry_has_opt (entry, "+noauto"))
906 hint_auto = FALSE;
907 }
908 g_list_free_full (fstab_entries, g_object_unref);
909
910 /* TODO: set ignore to TRUE for physical paths belonging to a drive with multiple paths */
911
912 /* Override from UDISKS_* udev properties */
913 if (g_udev_device_has_property (device->udev_device, "UDISKS_SYSTEM"))
914 hint_system = g_udev_device_get_property_as_boolean (device->udev_device, "UDISKS_SYSTEM");
915
916 if (g_udev_device_has_property (device->udev_device, "UDISKS_IGNORE"))
917 hint_ignore = g_udev_device_get_property_as_boolean (device->udev_device, "UDISKS_IGNORE");
918
919 if (g_udev_device_has_property (device->udev_device, "UDISKS_AUTO"))
920 hint_auto = g_udev_device_get_property_as_boolean (device->udev_device, "UDISKS_AUTO");
921
922 if (g_udev_device_has_property (device->udev_device, "UDISKS_NAME"))
923 hint_name = g_udev_device_get_property (device->udev_device, "UDISKS_NAME");
924
925 if (g_udev_device_has_property (device->udev_device, "UDISKS_ICON_NAME"))
926 hint_icon_name = g_udev_device_get_property (device->udev_device, "UDISKS_ICON_NAME");
927
928 if (g_udev_device_has_property (device->udev_device, "UDISKS_SYMBOLIC_ICON_NAME"))
929 hint_symbolic_icon_name = g_udev_device_get_property (device->udev_device, "UDISKS_SYMBOLIC_ICON_NAME");
930
931 /* ... and scene! */
932 udisks_block_set_hint_partitionable (iface, hint_partitionable);
933 udisks_block_set_hint_system (iface, hint_system);
934 udisks_block_set_hint_ignore (iface, hint_ignore);
935 udisks_block_set_hint_auto (iface, hint_auto);
936 udisks_block_set_hint_name (iface, hint_name);
937 udisks_block_set_hint_icon_name (iface, hint_icon_name);
938 udisks_block_set_hint_symbolic_icon_name (iface, hint_symbolic_icon_name);
939 }
940
941 /* ---------------------------------------------------------------------------------------------------- */
942
943 static gchar *
get_slave_sysfs_path(const gchar * sysfs_path)944 get_slave_sysfs_path (const gchar *sysfs_path)
945 {
946 gchar *ret = NULL;
947 gchar **slaves;
948 slaves = udisks_daemon_util_resolve_links (sysfs_path, "slaves");
949 if (slaves != NULL && g_strv_length (slaves) == 1)
950 {
951 ret = g_strdup (slaves[0]);
952 }
953
954 g_strfreev (slaves);
955 return ret;
956 }
957
958 /**
959 * udisks_linux_block_update:
960 * @block: A #UDisksLinuxBlock.
961 * @object: The enclosing #UDisksLinuxBlockObject instance.
962 *
963 * Updates the interface.
964 */
965 void
udisks_linux_block_update(UDisksLinuxBlock * block,UDisksLinuxBlockObject * object)966 udisks_linux_block_update (UDisksLinuxBlock *block,
967 UDisksLinuxBlockObject *object)
968 {
969 UDisksBlock *iface = UDISKS_BLOCK (block);
970 UDisksDaemon *daemon;
971 GDBusObjectManagerServer *object_manager;
972 UDisksLinuxDevice *device;
973 GUdevDeviceNumber dev;
974 gchar *drive_object_path;
975 UDisksDrive *drive;
976 gchar *s;
977 const gchar *device_file;
978 const gchar *const *symlinks;
979 const gchar *preferred_device_file;
980 const gchar *id_device_file;
981 gboolean media_removable = FALSE;
982 guint64 size;
983 gboolean media_available;
984 gboolean media_change_detected;
985 gboolean read_only;
986 gboolean seems_encrypted = FALSE;
987 guint n;
988 GError *error = NULL;
989
990 drive = NULL;
991
992 device = udisks_linux_block_object_get_device (object);
993 if (device == NULL)
994 goto out;
995
996 daemon = udisks_linux_block_object_get_daemon (object);
997 object_manager = udisks_daemon_get_object_manager (daemon);
998
999 dev = g_udev_device_get_device_number (device->udev_device);
1000 device_file = g_udev_device_get_device_file (device->udev_device);
1001 symlinks = g_udev_device_get_device_file_symlinks (device->udev_device);
1002
1003 udisks_block_set_device (iface, device_file);
1004 udisks_block_set_symlinks (iface, symlinks);
1005 udisks_block_set_device_number (iface, dev);
1006
1007 size = udisks_daemon_util_block_get_size (device->udev_device,
1008 &media_available,
1009 &media_change_detected);
1010 udisks_block_set_size (iface, size);
1011
1012 read_only = g_udev_device_get_sysfs_attr_as_boolean (device->udev_device, "ro");
1013 if (!read_only && g_str_has_prefix (g_udev_device_get_name (device->udev_device), "sr"))
1014 read_only = TRUE;
1015 udisks_block_set_read_only (iface, read_only);
1016
1017 /* dm-crypt
1018 *
1019 * TODO: this might not be the best way to determine if the device-mapper device
1020 * is a dm-crypt device.. but unfortunately device-mapper keeps all this stuff
1021 * in user-space and wants you to use libdevmapper to obtain it...
1022 */
1023 udisks_block_set_crypto_backing_device (iface, "/");
1024 if (g_str_has_prefix (g_udev_device_get_name (device->udev_device), "dm-"))
1025 {
1026 gchar *dm_uuid;
1027 dm_uuid = get_sysfs_attr (device->udev_device, "dm/uuid");
1028 if (dm_uuid != NULL &&
1029 (g_str_has_prefix (dm_uuid, "CRYPT-LUKS") || g_str_has_prefix (dm_uuid, "CRYPT-BITLK") || g_str_has_prefix (dm_uuid, "CRYPT-TCRYPT")))
1030 {
1031 gchar *slave_sysfs_path;
1032 slave_sysfs_path = get_slave_sysfs_path (g_udev_device_get_sysfs_path (device->udev_device));
1033
1034 while (slave_sysfs_path)
1035 {
1036 UDisksLinuxBlockObject *slave_object;
1037 slave_object = find_block_device_by_sysfs_path (object_manager, slave_sysfs_path);
1038 if (slave_object != NULL)
1039 {
1040 UDisksEncrypted *enc;
1041
1042 udisks_block_set_crypto_backing_device (iface,
1043 g_dbus_object_get_object_path (G_DBUS_OBJECT (slave_object)));
1044
1045 /* also set the CleartextDevice property for the parent device */
1046 enc = udisks_object_peek_encrypted (UDISKS_OBJECT (slave_object));
1047 if (enc != NULL)
1048 {
1049 udisks_encrypted_set_cleartext_device (UDISKS_ENCRYPTED (enc),
1050 g_dbus_object_get_object_path (G_DBUS_OBJECT (object)));
1051 }
1052
1053 g_object_unref (slave_object);
1054 g_free (slave_sysfs_path);
1055 break;
1056 }
1057 else
1058 {
1059 gchar *old_sysfs_path = slave_sysfs_path;
1060 slave_sysfs_path = get_slave_sysfs_path (old_sysfs_path);
1061 g_free (old_sysfs_path);
1062 }
1063 }
1064 }
1065 g_free (dm_uuid);
1066 }
1067
1068 /* Sort out preferred device... this is what UI shells should
1069 * display. We default to the block device name.
1070 *
1071 * This is mostly for things like device-mapper where device file is
1072 * a name of the form dm-%d and a symlink name conveys more
1073 * information.
1074 */
1075 preferred_device_file = NULL;
1076 if (g_str_has_prefix (device_file, "/dev/dm-"))
1077 {
1078 const gchar *dm_name;
1079 gchar *dm_name_dev_file = NULL;
1080 const gchar *dm_name_dev_file_as_symlink = NULL;
1081
1082 const gchar *dm_vg_name;
1083 const gchar *dm_lv_name;
1084 gchar *dm_lvm_dev_file = NULL;
1085
1086 dm_name = g_udev_device_get_property (device->udev_device, "DM_NAME");
1087 if (dm_name != NULL)
1088 dm_name_dev_file = g_strdup_printf ("/dev/mapper/%s", dm_name);
1089
1090 dm_vg_name = g_udev_device_get_property (device->udev_device, "DM_VG_NAME");
1091 dm_lv_name = g_udev_device_get_property (device->udev_device, "DM_LV_NAME");
1092 if (dm_vg_name != NULL && dm_lv_name != NULL)
1093 dm_lvm_dev_file = g_strdup_printf ("/dev/%s/%s", dm_vg_name, dm_lv_name);
1094
1095 for (n = 0; symlinks != NULL && symlinks[n] != NULL; n++)
1096 {
1097 if (g_str_has_prefix (symlinks[n], "/dev/vg_")
1098 || g_strcmp0 (symlinks[n], dm_lvm_dev_file) == 0)
1099 {
1100 /* LVM2 */
1101 preferred_device_file = symlinks[n];
1102 break;
1103 }
1104 else if (g_strcmp0 (symlinks[n], dm_name_dev_file) == 0)
1105 {
1106 dm_name_dev_file_as_symlink = symlinks[n];
1107 }
1108 }
1109 /* fall back to /dev/mapper/$DM_NAME, if available as a symlink */
1110 if (preferred_device_file == NULL && dm_name_dev_file_as_symlink != NULL)
1111 preferred_device_file = dm_name_dev_file_as_symlink;
1112 g_free (dm_name_dev_file);
1113 g_free (dm_lvm_dev_file);
1114 }
1115 else if (g_str_has_prefix (device_file, "/dev/md"))
1116 {
1117 for (n = 0; symlinks != NULL && symlinks[n] != NULL; n++)
1118 {
1119 if (g_str_has_prefix (symlinks[n], "/dev/md/"))
1120 {
1121 preferred_device_file = symlinks[n];
1122 break;
1123 }
1124 }
1125 }
1126 /* fallback to the device name */
1127 if (preferred_device_file == NULL)
1128 preferred_device_file = g_udev_device_get_device_file (device->udev_device);
1129 udisks_block_set_preferred_device (iface, preferred_device_file);
1130
1131 /* Determine the drive this block device belongs to
1132 *
1133 * TODO: if this is slow we could have a cache or ensure that we
1134 * only do this once or something else
1135 */
1136 drive_object_path = find_drive (object_manager, device->udev_device, &drive);
1137 if (drive_object_path != NULL)
1138 {
1139 udisks_block_set_drive (iface, drive_object_path);
1140 g_free (drive_object_path);
1141 }
1142 else
1143 {
1144 udisks_block_set_drive (iface, "/");
1145 }
1146
1147 if (drive != NULL)
1148 media_removable = udisks_drive_get_media_removable (drive);
1149
1150 id_device_file = NULL;
1151 if (media_removable)
1152 {
1153 /* Drive with removable media: determine id by finding a
1154 * suitable /dev/disk/by-uuid symlink (fall back to
1155 * /dev/disk/by-label)
1156 *
1157 * TODO: add features to ata_id / cdrom_id in systemd to extract
1158 * medium identiers (at optical discs have these) and add
1159 * udev rules to create symlinks in something like
1160 * /dev/disk/by-medium. Then use said symlinks to for the
1161 * id_device_file
1162 */
1163 for (n = 0; symlinks != NULL && symlinks[n] != NULL; n++)
1164 {
1165 if (g_str_has_prefix (symlinks[n], "/dev/disk/by-uuid/"))
1166 {
1167 id_device_file = symlinks[n];
1168 break;
1169 }
1170 else if (g_str_has_prefix (symlinks[n], "/dev/disk/by-label/"))
1171 {
1172 id_device_file = symlinks[n];
1173 }
1174 }
1175 }
1176 else
1177 {
1178 /* Drive without removable media: determine id by finding a
1179 * suitable /dev/disk/by-id symlink
1180 */
1181 for (n = 0; symlinks != NULL && symlinks[n] != NULL; n++)
1182 {
1183 if (g_str_has_prefix (symlinks[n], "/dev/disk/by-id/"))
1184 {
1185 id_device_file = symlinks[n];
1186 break;
1187 }
1188 }
1189 }
1190 if (id_device_file != NULL)
1191 {
1192 gchar *id = g_strdup (id_device_file + strlen ("/dev/disk/"));
1193 for (n = 0; id[n] != '\0'; n++)
1194 {
1195 if (id[n] == '/' || id[n] == ' ')
1196 id[n] = '-';
1197 }
1198 udisks_block_set_id (iface, id);
1199 g_free (id);
1200 }
1201 else
1202 {
1203 udisks_block_set_id (iface, NULL);
1204 }
1205
1206 if (udisks_daemon_get_enable_tcrypt (daemon))
1207 {
1208 seems_encrypted = bd_crypto_device_seems_encrypted (device_file, &error);
1209 if (error != NULL)
1210 {
1211 udisks_warning ("Error determining whether device '%s' seems to be encrypted: %s (%s, %d)",
1212 device_file, error->message, g_quark_to_string (error->domain), error->code);
1213 g_clear_error (&error);
1214 }
1215 }
1216
1217 if (seems_encrypted)
1218 {
1219 udisks_block_set_id_usage (iface, "crypto");
1220 udisks_block_set_id_type (iface, "crypto_unknown");
1221 }
1222 else
1223 {
1224 udisks_block_set_id_usage (iface, g_udev_device_get_property (device->udev_device, "ID_FS_USAGE"));
1225 udisks_block_set_id_type (iface, g_udev_device_get_property (device->udev_device, "ID_FS_TYPE"));
1226 }
1227
1228 s = udisks_decode_udev_string (g_udev_device_get_property (device->udev_device, "ID_FS_VERSION"), NULL);
1229 udisks_block_set_id_version (iface, s);
1230 g_free (s);
1231 s = udisks_decode_udev_string (g_udev_device_get_property (device->udev_device, "ID_FS_LABEL_ENC"),
1232 g_udev_device_get_property (device->udev_device, "ID_FS_LABEL"));
1233 udisks_block_set_id_label (iface, s);
1234 g_free (s);
1235 s = udisks_decode_udev_string (g_udev_device_get_property (device->udev_device, "ID_FS_UUID_ENC"),
1236 g_udev_device_get_property (device->udev_device, "ID_FS_UUID"));
1237 udisks_block_set_id_uuid (iface, s);
1238 g_free (s);
1239
1240 update_hints (daemon, block, device, drive);
1241 update_configuration (block, daemon);
1242 #ifdef HAVE_LIBMOUNT_UTAB
1243 update_userspace_mount_options (block, daemon);
1244 #endif
1245 update_mdraid (block, device, drive, object_manager);
1246
1247 out:
1248 g_dbus_interface_skeleton_flush (G_DBUS_INTERFACE_SKELETON (block));
1249 if (device != NULL)
1250 g_object_unref (device);
1251 if (drive != NULL)
1252 g_object_unref (drive);
1253 }
1254
1255 /* ---------------------------------------------------------------------------------------------------- */
1256
1257 static gboolean
handle_get_secret_configuration(UDisksBlock * _block,GDBusMethodInvocation * invocation,GVariant * options)1258 handle_get_secret_configuration (UDisksBlock *_block,
1259 GDBusMethodInvocation *invocation,
1260 GVariant *options)
1261 {
1262 UDisksLinuxBlock *block = UDISKS_LINUX_BLOCK (_block);
1263 UDisksLinuxBlockObject *object;
1264 UDisksDaemon *daemon;
1265 GVariant *configuration;
1266 GError *error;
1267
1268 error = NULL;
1269 object = udisks_daemon_util_dup_object (block, &error);
1270 if (object == NULL)
1271 {
1272 g_dbus_method_invocation_take_error (invocation, error);
1273 goto out;
1274 }
1275
1276 daemon = udisks_linux_block_object_get_daemon (object);
1277
1278 error = NULL;
1279 configuration = calculate_configuration (block, daemon, TRUE, &error);
1280 if (configuration == NULL)
1281 {
1282 g_dbus_method_invocation_take_error (invocation, error);
1283 goto out;
1284 }
1285
1286 if (!udisks_daemon_util_check_authorization_sync (daemon,
1287 NULL,
1288 "org.freedesktop.udisks2.read-system-configuration-secrets",
1289 options,
1290 /* Translators: This is shown in an authentcation dialog when
1291 * the user is editing settings that involve system-level
1292 * passwords and secrets
1293 */
1294 N_("Authentication is required to read system-level secrets"),
1295 invocation))
1296 {
1297 g_variant_unref (configuration);
1298 goto out;
1299 }
1300
1301 udisks_block_complete_get_secret_configuration (UDISKS_BLOCK (block),
1302 invocation,
1303 configuration); /* consumes floating ref */
1304
1305 out:
1306 g_clear_object (&object);
1307 return TRUE; /* returning TRUE means that we handled the method invocation */
1308 }
1309
1310 /* ---------------------------------------------------------------------------------------------------- */
1311
1312 static gchar *
escape_fstab(const gchar * source)1313 escape_fstab (const gchar *source)
1314 {
1315 GString *s;
1316 guint n;
1317 s = g_string_new (NULL);
1318 for (n = 0; source[n] != '\0'; n++)
1319 {
1320 switch (source[n])
1321 {
1322 case ' ':
1323 case '\t':
1324 case '\n':
1325 case '\\':
1326 g_string_append_printf (s, "\\%03o", (guint) source[n]);
1327 break;
1328
1329 default:
1330 g_string_append_c (s, source[n]);
1331 break;
1332 }
1333 }
1334 return g_string_free (s, FALSE);
1335 }
1336
1337 /* based on g_strcompress() */
1338 static gchar *
unescape_fstab(const gchar * source)1339 unescape_fstab (const gchar *source)
1340 {
1341 const gchar *p = source, *octal;
1342 gchar *dest = g_malloc (strlen (source) + 1);
1343 gchar *q = dest;
1344
1345 while (*p)
1346 {
1347 if (*p == '\\')
1348 {
1349 p++;
1350 switch (*p)
1351 {
1352 case '\0':
1353 udisks_warning ("unescape_fstab: trailing \\");
1354 goto out;
1355 case '0': case '1': case '2': case '3': case '4':
1356 case '5': case '6': case '7':
1357 *q = 0;
1358 octal = p;
1359 while ((p < octal + 3) && (*p >= '0') && (*p <= '7'))
1360 {
1361 *q = (*q * 8) + (*p - '0');
1362 p++;
1363 }
1364 q++;
1365 p--;
1366 break;
1367 default: /* Also handles \" and \\ */
1368 *q++ = *p;
1369 break;
1370 }
1371 }
1372 else
1373 *q++ = *p;
1374 p++;
1375 }
1376 out:
1377 *q = 0;
1378
1379 return dest;
1380 }
1381
1382 /* ---------------------------------------------------------------------------------------------------- */
1383
1384 static gchar *
make_block_fsname(UDisksBlock * block)1385 make_block_fsname (UDisksBlock *block)
1386 {
1387 const gchar *uuid = udisks_block_get_id_uuid (block);
1388
1389 if (uuid && *uuid)
1390 return g_strdup_printf ("UUID=%s", uuid);
1391 else
1392 return g_strdup (udisks_block_get_device (block));
1393 }
1394
1395 static gchar *
track_parents(UDisksBlock * block,const gchar * options)1396 track_parents (UDisksBlock *block, const gchar *options)
1397 {
1398 UDisksObject *object = UDISKS_OBJECT (g_dbus_interface_get_object (G_DBUS_INTERFACE (block)));
1399 UDisksDaemon *daemon = udisks_linux_block_object_get_daemon (UDISKS_LINUX_BLOCK_OBJECT (object));
1400
1401 gchar *new_options, *start, *end, *path;
1402
1403 /* Remove old x-parent entries
1404 */
1405 new_options = g_strdup (options);
1406 start = new_options;
1407 while ((start = strstr (start, "x-parent=")) != NULL)
1408 {
1409 end = strchr (start, ',');
1410 if (end)
1411 strcpy (start, end+1);
1412 else
1413 *start = '\0';
1414 }
1415
1416 /* Walk up our ancestry and give each parent a chance to be tracked.
1417 */
1418 path = g_strdup (g_dbus_object_get_object_path (G_DBUS_OBJECT (object)));
1419 do
1420 {
1421 gchar *uuid = NULL;
1422 gchar *parent_path = udisks_daemon_get_parent_for_tracking (daemon, path, &uuid);
1423
1424 if (uuid && *uuid)
1425 {
1426 gchar *new;
1427 if (new_options && *new_options)
1428 new = g_strdup_printf ("%s,x-parent=%s", new_options, uuid);
1429 else
1430 new = g_strdup_printf ("x-parent=%s", uuid);
1431 g_free (new_options);
1432 new_options = new;
1433 }
1434
1435 g_free (uuid);
1436 g_free (path);
1437 path = parent_path;
1438 }
1439 while (path);
1440
1441 return new_options;
1442 }
1443
1444 static gboolean
add_remove_fstab_entry(UDisksBlock * block,GVariant * remove,GVariant * add,GError ** error)1445 add_remove_fstab_entry (UDisksBlock *block,
1446 GVariant *remove,
1447 GVariant *add,
1448 GError **error)
1449 {
1450 struct mntent mntent_remove;
1451 struct mntent mntent_add;
1452 gboolean track_parents_flag;
1453 gboolean ret;
1454 gchar *auto_fsname = NULL;
1455 gchar *auto_opts = NULL;
1456 gchar *contents;
1457 gchar **lines;
1458 GString *str;
1459 gboolean removed;
1460 guint n;
1461
1462 contents = NULL;
1463 lines = NULL;
1464 str = NULL;
1465 ret = FALSE;
1466
1467 if (remove != NULL)
1468 {
1469 if (!g_variant_lookup (remove, "fsname", "^&ay", &mntent_remove.mnt_fsname) ||
1470 !g_variant_lookup (remove, "dir", "^&ay", &mntent_remove.mnt_dir) ||
1471 !g_variant_lookup (remove, "type", "^&ay", &mntent_remove.mnt_type) ||
1472 !g_variant_lookup (remove, "opts", "^&ay", &mntent_remove.mnt_opts) ||
1473 !g_variant_lookup (remove, "freq", "i", &mntent_remove.mnt_freq) ||
1474 !g_variant_lookup (remove, "passno", "i", &mntent_remove.mnt_passno))
1475 {
1476 g_set_error (error,
1477 UDISKS_ERROR,
1478 UDISKS_ERROR_FAILED,
1479 "Missing fsname, dir, type, opts, freq or passno parameter in entry to remove");
1480 goto out;
1481 }
1482 }
1483
1484 if (add != NULL)
1485 {
1486 if (!g_variant_lookup (add, "fsname", "^&ay", &mntent_add.mnt_fsname))
1487 {
1488 auto_fsname = make_block_fsname (block);
1489 mntent_add.mnt_fsname = auto_fsname;
1490 }
1491
1492 if (!g_variant_lookup (add, "dir", "^&ay", &mntent_add.mnt_dir) ||
1493 !g_variant_lookup (add, "type", "^&ay", &mntent_add.mnt_type) ||
1494 !g_variant_lookup (add, "opts", "^&ay", &mntent_add.mnt_opts) ||
1495 !g_variant_lookup (add, "freq", "i", &mntent_add.mnt_freq) ||
1496 !g_variant_lookup (add, "passno", "i", &mntent_add.mnt_passno))
1497 {
1498 g_set_error (error,
1499 UDISKS_ERROR,
1500 UDISKS_ERROR_FAILED,
1501 "Missing dir, type, opts, freq or passno parameter in entry to add");
1502 goto out;
1503 }
1504
1505 if (strlen (mntent_add.mnt_opts) == 0)
1506 {
1507 g_set_error (error,
1508 UDISKS_ERROR,
1509 UDISKS_ERROR_FAILED,
1510 "opts must not be blank");
1511 goto out;
1512 }
1513
1514 if (g_variant_lookup (add, "track-parents", "b", &track_parents_flag) &&
1515 track_parents_flag)
1516 {
1517 auto_opts = track_parents (block, mntent_add.mnt_opts);
1518 mntent_add.mnt_opts = auto_opts;
1519 }
1520 }
1521
1522 if (!g_file_get_contents ("/etc/fstab",
1523 &contents,
1524 NULL,
1525 error))
1526 goto out;
1527
1528 lines = g_strsplit (contents, "\n", 0);
1529
1530 str = g_string_new (NULL);
1531 removed = FALSE;
1532 for (n = 0; lines != NULL && lines[n] != NULL; n++)
1533 {
1534 const gchar *line = lines[n];
1535 if (strlen (line) == 0 && lines[n+1] == NULL)
1536 break;
1537 if (remove != NULL && !removed)
1538 {
1539 gchar parsed_fsname[512];
1540 gchar parsed_dir[512];
1541 gchar parsed_type[512];
1542 gchar parsed_opts[512];
1543 gint parsed_freq;
1544 gint parsed_passno;
1545 if (sscanf (line, "%511s %511s %511s %511s %d %d",
1546 parsed_fsname,
1547 parsed_dir,
1548 parsed_type,
1549 parsed_opts,
1550 &parsed_freq,
1551 &parsed_passno) == 6)
1552 {
1553 gchar *unescaped_fsname = unescape_fstab (parsed_fsname);
1554 gchar *unescaped_dir = unescape_fstab (parsed_dir);
1555 gchar *unescaped_type = unescape_fstab (parsed_type);
1556 gchar *unescaped_opts = unescape_fstab (parsed_opts);
1557 gboolean matches = FALSE;
1558 if (g_strcmp0 (unescaped_fsname, mntent_remove.mnt_fsname) == 0 &&
1559 g_strcmp0 (unescaped_dir, mntent_remove.mnt_dir) == 0 &&
1560 g_strcmp0 (unescaped_type, mntent_remove.mnt_type) == 0 &&
1561 g_strcmp0 (unescaped_opts, mntent_remove.mnt_opts) == 0 &&
1562 parsed_freq == mntent_remove.mnt_freq &&
1563 parsed_passno == mntent_remove.mnt_passno)
1564 {
1565 matches = TRUE;
1566 }
1567 g_free (unescaped_fsname);
1568 g_free (unescaped_dir);
1569 g_free (unescaped_type);
1570 g_free (unescaped_opts);
1571 if (matches)
1572 {
1573 removed = TRUE;
1574 continue;
1575 }
1576 }
1577 }
1578 g_string_append (str, line);
1579 g_string_append_c (str, '\n');
1580 }
1581
1582 if (remove != NULL && !removed)
1583 {
1584 g_set_error (error,
1585 UDISKS_ERROR,
1586 UDISKS_ERROR_FAILED,
1587 "Didn't find entry to remove");
1588 goto out;
1589 }
1590
1591 if (add != NULL)
1592 {
1593 gchar *escaped_fsname = escape_fstab (mntent_add.mnt_fsname);
1594 gchar *escaped_dir = escape_fstab (mntent_add.mnt_dir);
1595 gchar *escaped_type = escape_fstab (mntent_add.mnt_type);
1596 gchar *escaped_opts = escape_fstab (mntent_add.mnt_opts);
1597 g_string_append_printf (str, "%s %s %s %s %d %d\n",
1598 escaped_fsname,
1599 escaped_dir,
1600 escaped_type,
1601 escaped_opts,
1602 mntent_add.mnt_freq,
1603 mntent_add.mnt_passno);
1604 g_free (escaped_fsname);
1605 g_free (escaped_dir);
1606 g_free (escaped_type);
1607 g_free (escaped_opts);
1608 }
1609
1610 if (!udisks_daemon_util_file_set_contents ("/etc/fstab",
1611 str->str,
1612 -1,
1613 0644, /* mode to use if non-existent */
1614 error))
1615 goto out;
1616
1617 ret = TRUE;
1618
1619 out:
1620 g_free (auto_opts);
1621 g_free (auto_fsname);
1622 g_strfreev (lines);
1623 g_free (contents);
1624 if (str != NULL)
1625 g_string_free (str, TRUE);
1626 return ret;
1627 }
1628
1629 /* ---------------------------------------------------------------------------------------------------- */
1630
1631 static gboolean
has_whitespace(const gchar * s)1632 has_whitespace (const gchar *s)
1633 {
1634 guint n;
1635 g_return_val_if_fail (s != NULL, TRUE);
1636 for (n = 0; s[n] != '\0'; n++)
1637 if (g_ascii_isspace (s[n]))
1638 return TRUE;
1639 return FALSE;
1640 }
1641
1642 static gchar *
make_block_luksname(UDisksBlock * block,GError ** error)1643 make_block_luksname (UDisksBlock *block, GError **error)
1644 {
1645 gchar *uuid = NULL;
1646
1647 udisks_linux_block_encrypted_lock (block);
1648 uuid = bd_crypto_luks_uuid (udisks_block_get_device (block), error);
1649 udisks_linux_block_encrypted_unlock (block);
1650
1651 if (uuid)
1652 {
1653 gchar *ret = g_strdup_printf ("luks-%s", uuid);
1654 g_free (uuid);
1655
1656 return ret;
1657 }
1658 else
1659 return NULL;
1660 }
1661
1662 static gboolean
add_remove_crypttab_entry(UDisksBlock * block,GVariant * remove,GVariant * add,GError ** error)1663 add_remove_crypttab_entry (UDisksBlock *block,
1664 GVariant *remove,
1665 GVariant *add,
1666 GError **error)
1667 {
1668 const gchar *remove_name = NULL;
1669 const gchar *remove_device = NULL;
1670 const gchar *remove_passphrase_path = NULL;
1671 const gchar *remove_options = NULL;
1672 const gchar *add_name = NULL;
1673 const gchar *add_device = NULL;
1674 const gchar *add_passphrase_path = NULL;
1675 const gchar *add_options = NULL;
1676 const gchar *add_passphrase_contents = NULL;
1677 gboolean track_parents_flag;
1678 gboolean ret;
1679 gchar *auto_name = NULL;
1680 gchar *auto_device = NULL;
1681 gchar *auto_passphrase_path = NULL;
1682 gchar *auto_opts = NULL;
1683 gchar *contents;
1684 gchar **lines;
1685 GString *str;
1686 gboolean removed;
1687 guint n;
1688
1689 contents = NULL;
1690 lines = NULL;
1691 str = NULL;
1692 ret = FALSE;
1693
1694 if (remove != NULL)
1695 {
1696 if (!g_variant_lookup (remove, "name", "^&ay", &remove_name) ||
1697 !g_variant_lookup (remove, "device", "^&ay", &remove_device) ||
1698 !g_variant_lookup (remove, "passphrase-path", "^&ay", &remove_passphrase_path) ||
1699 !g_variant_lookup (remove, "options", "^&ay", &remove_options))
1700 {
1701 g_set_error (error,
1702 UDISKS_ERROR,
1703 UDISKS_ERROR_FAILED,
1704 "Missing name, device, passphrase-path, options or parameter in entry to remove");
1705 goto out;
1706 }
1707 }
1708
1709 if (add != NULL)
1710 {
1711 if (!g_variant_lookup (add, "name", "^&ay", &add_name))
1712 {
1713 const gchar *uuid = udisks_block_get_id_uuid (block);
1714 if (uuid == NULL || *uuid == '\0')
1715 {
1716 g_set_error (error,
1717 UDISKS_ERROR,
1718 UDISKS_ERROR_FAILED,
1719 "Block device has no UUID, can't determine default name");
1720 goto out;
1721 }
1722
1723 auto_name = g_strdup_printf ("luks-%s", uuid);
1724 add_name = auto_name;
1725 }
1726
1727 if (!g_variant_lookup (add, "device", "^&ay", &add_device))
1728 {
1729 auto_device = make_block_fsname (block);
1730 add_device = auto_device;
1731 }
1732
1733 if (!g_variant_lookup (add, "options", "^&ay", &add_options) ||
1734 !g_variant_lookup (add, "passphrase-contents", "^&ay", &add_passphrase_contents))
1735 {
1736 g_set_error (error,
1737 UDISKS_ERROR,
1738 UDISKS_ERROR_FAILED,
1739 "Missing options or passphrase-contents parameter in entry to add");
1740 goto out;
1741 }
1742
1743 if (!g_variant_lookup (add, "passphrase-path", "^&ay", &add_passphrase_path))
1744 {
1745 if (*add_passphrase_contents == '\0')
1746 add_passphrase_path = "";
1747 else
1748 {
1749 auto_passphrase_path = g_strdup_printf ("/etc/luks-keys/%s", add_name);
1750 add_passphrase_path = auto_passphrase_path;
1751 }
1752 }
1753
1754 /* reject strings with whitespace in them */
1755 if (has_whitespace (add_name) ||
1756 has_whitespace (add_device) ||
1757 has_whitespace (add_passphrase_path) ||
1758 has_whitespace (add_options))
1759 {
1760 g_set_error (error,
1761 UDISKS_ERROR,
1762 UDISKS_ERROR_FAILED,
1763 "One of name, device, passphrase-path or options parameter are invalid (whitespace)");
1764 goto out;
1765 }
1766
1767 if (g_variant_lookup (add, "track-parents", "b", &track_parents_flag) &&
1768 track_parents_flag)
1769 {
1770 auto_opts = track_parents (block, add_options);
1771 add_options = auto_opts;
1772 }
1773 }
1774
1775 if (!g_file_get_contents ("/etc/crypttab",
1776 &contents,
1777 NULL,
1778 error))
1779 {
1780 if (g_error_matches (*error, G_FILE_ERROR, G_FILE_ERROR_NOENT))
1781 {
1782 contents = g_strdup ("");
1783 g_clear_error (error);
1784 }
1785 else
1786 goto out;
1787 }
1788
1789 lines = g_strsplit (contents, "\n", 0);
1790
1791 str = g_string_new (NULL);
1792 removed = FALSE;
1793 for (n = 0; lines != NULL && lines[n] != NULL; n++)
1794 {
1795 const gchar *line = lines[n];
1796 if (strlen (line) == 0 && lines[n+1] == NULL)
1797 break;
1798 if (remove != NULL && !removed)
1799 {
1800 gchar parsed_name[512];
1801 gchar parsed_device[512];
1802 gchar parsed_passphrase_path[512];
1803 gchar parsed_options[512];
1804 guint num_parsed;
1805
1806 num_parsed = sscanf (line, "%511s %511s %511s %511s",
1807 parsed_name, parsed_device, parsed_passphrase_path, parsed_options);
1808 if (num_parsed >= 2)
1809 {
1810 if (num_parsed < 3 || g_strcmp0 (parsed_passphrase_path, "none") == 0)
1811 strcpy (parsed_passphrase_path, "");
1812 if (num_parsed < 4)
1813 strcpy (parsed_options, "");
1814 if (g_strcmp0 (parsed_name, remove_name) == 0 &&
1815 g_strcmp0 (parsed_device, remove_device) == 0 &&
1816 g_strcmp0 (parsed_passphrase_path, remove_passphrase_path) == 0 &&
1817 g_strcmp0 (parsed_options, remove_options) == 0)
1818 {
1819 /* Nuke passphrase file */
1820 if (strlen (remove_passphrase_path) > 0 && !g_str_has_prefix (remove_passphrase_path, "/dev"))
1821 {
1822 /* Is this exploitable? No, 1. the user would have to control
1823 * the /etc/crypttab file for us to delete it; and 2. editing the
1824 * /etc/crypttab file requires a polkit authorization that can't
1825 * be retained (e.g. the user is always asked for the password)..
1826 */
1827 if (unlink (remove_passphrase_path) != 0)
1828 {
1829 g_set_error (error,
1830 UDISKS_ERROR,
1831 UDISKS_ERROR_FAILED,
1832 "Error deleting file `%s' with passphrase",
1833 remove_passphrase_path);
1834 goto out;
1835 }
1836 }
1837 removed = TRUE;
1838 continue;
1839 }
1840 }
1841 }
1842 g_string_append (str, line);
1843 g_string_append_c (str, '\n');
1844 }
1845
1846 if (remove != NULL && !removed)
1847 {
1848 g_set_error (error,
1849 UDISKS_ERROR,
1850 UDISKS_ERROR_FAILED,
1851 "Didn't find entry to remove");
1852 goto out;
1853 }
1854
1855 if (add != NULL)
1856 {
1857 /* First write add_passphrase_content to add_passphrase_path,
1858 * if applicable..
1859 *
1860 * Is this exploitable? No, because editing the /etc/crypttab
1861 * file requires a polkit authorization that can't be retained
1862 * (e.g. the user is always asked for the password)...
1863 *
1864 * Just to be on the safe side we only allow writing into the
1865 * directory /etc/luks-keys if create a _new_ entry.
1866 */
1867 if (strlen (add_passphrase_path) > 0)
1868 {
1869 gchar *filename;
1870 if (g_strcmp0 (add_passphrase_path, remove_passphrase_path) == 0)
1871 {
1872 filename = g_strdup (add_passphrase_path);
1873 }
1874 else
1875 {
1876 if (!g_str_has_prefix (add_passphrase_path, "/etc/luks-keys/"))
1877 {
1878 g_set_error (error,
1879 UDISKS_ERROR,
1880 UDISKS_ERROR_FAILED,
1881 "Crypttab passphrase file can only be created in the /etc/luks-keys directory");
1882 goto out;
1883 }
1884 /* ensure the directory exists */
1885 if (g_mkdir_with_parents ("/etc/luks-keys", 0700) != 0)
1886 {
1887 g_set_error (error,
1888 UDISKS_ERROR,
1889 UDISKS_ERROR_FAILED,
1890 "Error creating /etc/luks-keys directory: %m");
1891 goto out;
1892 }
1893 /* avoid symlink attacks */
1894 filename = g_strdup_printf ("/etc/luks-keys/%s", strrchr (add_passphrase_path, '/') + 1);
1895 }
1896
1897 /* Bail if the requested file already exists */
1898 if (g_file_test (filename, G_FILE_TEST_EXISTS))
1899 {
1900 g_set_error (error,
1901 UDISKS_ERROR,
1902 UDISKS_ERROR_FAILED,
1903 "Refusing to overwrite existing file %s",
1904 filename);
1905 g_free (filename);
1906 goto out;
1907 }
1908
1909 if (!udisks_daemon_util_file_set_contents (filename,
1910 add_passphrase_contents,
1911 -1,
1912 0600, /* mode to use if non-existent */
1913 error))
1914 {
1915 g_free (filename);
1916 goto out;
1917 }
1918 g_free (filename);
1919 }
1920 g_string_append_printf (str, "%s %s %s %s\n",
1921 add_name,
1922 add_device,
1923 strlen (add_passphrase_path) > 0 ? add_passphrase_path : "none",
1924 add_options);
1925 }
1926
1927 if (!udisks_daemon_util_file_set_contents ("/etc/crypttab",
1928 str->str,
1929 -1,
1930 0600, /* mode to use if non-existent */
1931 error))
1932 goto out;
1933
1934 ret = TRUE;
1935
1936 out:
1937 g_free (auto_opts);
1938 g_free (auto_name);
1939 g_free (auto_device);
1940 g_free (auto_passphrase_path);
1941 g_strfreev (lines);
1942 g_free (contents);
1943 if (str != NULL)
1944 g_string_free (str, TRUE);
1945 return ret;
1946 }
1947
1948 /* ---------------------------------------------------------------------------------------------------- */
1949
1950 static void
update_block_fstab(UDisksDaemon * daemon,UDisksLinuxBlock * block,UDisksLinuxBlockObject * object)1951 update_block_fstab (UDisksDaemon *daemon,
1952 UDisksLinuxBlock *block,
1953 UDisksLinuxBlockObject *object)
1954 {
1955 UDisksLinuxDevice *device;
1956 gchar *drive_object_path;
1957 UDisksDrive *drive = NULL;
1958
1959 update_configuration (block, daemon);
1960
1961 /* hints take fstab records in the calculation */
1962 device = udisks_linux_block_object_get_device (object);
1963 drive_object_path = find_drive (udisks_daemon_get_object_manager (daemon), device->udev_device, &drive);
1964 update_hints (daemon, block, device, drive);
1965 g_free (drive_object_path);
1966 g_clear_object (&device);
1967 g_clear_object (&drive);
1968 }
1969
1970 static gboolean
handle_add_configuration_item(UDisksBlock * _block,GDBusMethodInvocation * invocation,GVariant * item,GVariant * options)1971 handle_add_configuration_item (UDisksBlock *_block,
1972 GDBusMethodInvocation *invocation,
1973 GVariant *item,
1974 GVariant *options)
1975 {
1976 UDisksLinuxBlock *block = UDISKS_LINUX_BLOCK (_block);
1977 UDisksLinuxBlockObject *object;
1978 UDisksDaemon *daemon;
1979 const gchar *type;
1980 GVariant *details = NULL;
1981 GError *error;
1982
1983 error = NULL;
1984 object = udisks_daemon_util_dup_object (block, &error);
1985 if (object == NULL)
1986 {
1987 g_dbus_method_invocation_take_error (invocation, error);
1988 goto out;
1989 }
1990
1991 daemon = udisks_linux_block_object_get_daemon (object);
1992
1993 g_variant_get (item, "(&s@a{sv})", &type, &details);
1994 if (g_strcmp0 (type, "fstab") == 0)
1995 {
1996 if (!udisks_daemon_util_check_authorization_sync (daemon,
1997 NULL,
1998 "org.freedesktop.udisks2.modify-system-configuration",
1999 options,
2000 /* Translators: shown in authentication dialog - do not translate /etc/fstab */
2001 N_("Authentication is required to add an entry to the /etc/fstab file"),
2002 invocation))
2003 goto out;
2004 error = NULL;
2005 if (!add_remove_fstab_entry (_block, NULL, details, &error))
2006 {
2007 g_dbus_method_invocation_take_error (invocation, error);
2008 goto out;
2009 }
2010 update_block_fstab (daemon, block, object);
2011 udisks_block_complete_add_configuration_item (UDISKS_BLOCK (block), invocation);
2012 }
2013 else if (g_strcmp0 (type, "crypttab") == 0)
2014 {
2015 if (!udisks_daemon_util_check_authorization_sync (daemon,
2016 NULL,
2017 "org.freedesktop.udisks2.modify-system-configuration",
2018 options,
2019 /* Translators: shown in authentication dialog - do not tranlsate /etc/crypttab */
2020 N_("Authentication is required to add an entry to the /etc/crypttab file"),
2021 invocation))
2022 goto out;
2023 error = NULL;
2024 if (!add_remove_crypttab_entry (_block, NULL, details, &error))
2025 {
2026 g_dbus_method_invocation_take_error (invocation, error);
2027 goto out;
2028 }
2029 update_configuration (block, daemon);
2030 udisks_block_complete_add_configuration_item (UDISKS_BLOCK (block), invocation);
2031 }
2032 else
2033 {
2034 g_dbus_method_invocation_return_error (invocation,
2035 UDISKS_ERROR,
2036 UDISKS_ERROR_FAILED,
2037 "Only /etc/fstab or /etc/crypttab items can be added");
2038 goto out;
2039 }
2040
2041 out:
2042 g_variant_unref (details);
2043 g_clear_object (&object);
2044 return TRUE; /* returning TRUE means that we handled the method invocation */
2045 }
2046
2047 /* ---------------------------------------------------------------------------------------------------- */
2048
2049 static gboolean
handle_remove_configuration_item(UDisksBlock * _block,GDBusMethodInvocation * invocation,GVariant * item,GVariant * options)2050 handle_remove_configuration_item (UDisksBlock *_block,
2051 GDBusMethodInvocation *invocation,
2052 GVariant *item,
2053 GVariant *options)
2054 {
2055 UDisksLinuxBlock *block = UDISKS_LINUX_BLOCK (_block);
2056 UDisksLinuxBlockObject *object;
2057 UDisksDaemon *daemon;
2058 const gchar *type;
2059 GVariant *details = NULL;
2060 GError *error;
2061
2062 error = NULL;
2063 object = udisks_daemon_util_dup_object (block, &error);
2064 if (object == NULL)
2065 {
2066 g_dbus_method_invocation_take_error (invocation, error);
2067 goto out;
2068 }
2069
2070 daemon = udisks_linux_block_object_get_daemon (object);
2071
2072 g_variant_get (item, "(&s@a{sv})", &type, &details);
2073 if (g_strcmp0 (type, "fstab") == 0)
2074 {
2075 if (!udisks_daemon_util_check_authorization_sync (daemon,
2076 NULL,
2077 "org.freedesktop.udisks2.modify-system-configuration",
2078 options,
2079 /* Translators: shown in authentication dialog - do not translate /etc/fstab */
2080 N_("Authentication is required to remove an entry from /etc/fstab file"),
2081 invocation))
2082 goto out;
2083 error = NULL;
2084 if (!add_remove_fstab_entry (_block, details, NULL, &error))
2085 {
2086 g_dbus_method_invocation_take_error (invocation, error);
2087 goto out;
2088 }
2089 update_block_fstab (daemon, block, object);
2090 udisks_block_complete_remove_configuration_item (UDISKS_BLOCK (block), invocation);
2091 }
2092 else if (g_strcmp0 (type, "crypttab") == 0)
2093 {
2094 if (!udisks_daemon_util_check_authorization_sync (daemon,
2095 NULL,
2096 "org.freedesktop.udisks2.modify-system-configuration",
2097 options,
2098 /* Translators: shown in authentication dialog - do not translate /etc/crypttab */
2099 N_("Authentication is required to remove an entry from the /etc/crypttab file"),
2100 invocation))
2101 goto out;
2102 error = NULL;
2103 if (!add_remove_crypttab_entry (_block, details, NULL, &error))
2104 {
2105 g_dbus_method_invocation_take_error (invocation, error);
2106 goto out;
2107 }
2108 update_configuration (block, daemon);
2109 udisks_block_complete_remove_configuration_item (UDISKS_BLOCK (block), invocation);
2110 }
2111 else
2112 {
2113 g_dbus_method_invocation_return_error (invocation,
2114 UDISKS_ERROR,
2115 UDISKS_ERROR_FAILED,
2116 "Only fstab or crypttab items can be removed");
2117 goto out;
2118 }
2119
2120 out:
2121 g_variant_unref (details);
2122 g_clear_object (&object);
2123 return TRUE; /* returning TRUE means that we handled the method invocation */
2124 }
2125
2126 /* ---------------------------------------------------------------------------------------------------- */
2127
2128 static gboolean
handle_update_configuration_item(UDisksBlock * _block,GDBusMethodInvocation * invocation,GVariant * old_item,GVariant * new_item,GVariant * options)2129 handle_update_configuration_item (UDisksBlock *_block,
2130 GDBusMethodInvocation *invocation,
2131 GVariant *old_item,
2132 GVariant *new_item,
2133 GVariant *options)
2134 {
2135 UDisksLinuxBlock *block = UDISKS_LINUX_BLOCK (_block);
2136 UDisksLinuxBlockObject *object;
2137 UDisksDaemon *daemon;
2138 const gchar *old_type;
2139 const gchar *new_type;
2140 GVariant *old_details = NULL;
2141 GVariant *new_details = NULL;
2142 GError *error;
2143
2144 error = NULL;
2145 object = udisks_daemon_util_dup_object (block, &error);
2146 if (object == NULL)
2147 {
2148 g_dbus_method_invocation_take_error (invocation, error);
2149 goto out;
2150 }
2151
2152 daemon = udisks_linux_block_object_get_daemon (object);
2153
2154 g_variant_get (old_item, "(&s@a{sv})", &old_type, &old_details);
2155 g_variant_get (new_item, "(&s@a{sv})", &new_type, &new_details);
2156 if (g_strcmp0 (old_type, new_type) != 0)
2157 {
2158 g_dbus_method_invocation_return_error (invocation,
2159 UDISKS_ERROR,
2160 UDISKS_ERROR_FAILED,
2161 "old and new item are not of the same type");
2162 goto out;
2163 }
2164
2165 if (g_strcmp0 (old_type, "fstab") == 0)
2166 {
2167 if (!udisks_daemon_util_check_authorization_sync (daemon,
2168 NULL,
2169 "org.freedesktop.udisks2.modify-system-configuration",
2170 options,
2171 /* Translators: shown in authentication dialog - do not translate /etc/fstab */
2172 N_("Authentication is required to modify the /etc/fstab file"),
2173 invocation))
2174 goto out;
2175 error = NULL;
2176 if (!add_remove_fstab_entry (_block, old_details, new_details, &error))
2177 {
2178 g_dbus_method_invocation_take_error (invocation, error);
2179 goto out;
2180 }
2181 update_block_fstab (daemon, block, object);
2182 udisks_block_complete_update_configuration_item (UDISKS_BLOCK (block), invocation);
2183 }
2184 else if (g_strcmp0 (old_type, "crypttab") == 0)
2185 {
2186 if (!udisks_daemon_util_check_authorization_sync (daemon,
2187 NULL,
2188 "org.freedesktop.udisks2.modify-system-configuration",
2189 options,
2190 /* Translators: shown in authentication dialog - do not translate /etc/crypttab */
2191 N_("Authentication is required to modify the /etc/crypttab file"),
2192 invocation))
2193 goto out;
2194 error = NULL;
2195 if (!add_remove_crypttab_entry (_block, old_details, new_details, &error))
2196 {
2197 g_dbus_method_invocation_take_error (invocation, error);
2198 goto out;
2199 }
2200 update_configuration (block, daemon);
2201 udisks_block_complete_update_configuration_item (UDISKS_BLOCK (block), invocation);
2202 }
2203 else
2204 {
2205 g_dbus_method_invocation_return_error (invocation,
2206 UDISKS_ERROR,
2207 UDISKS_ERROR_FAILED,
2208 "Only fstab or crypttab items can be updated");
2209 goto out;
2210 }
2211
2212 out:
2213 g_variant_unref (new_details);
2214 g_variant_unref (old_details);
2215 g_clear_object (&object);
2216 return TRUE; /* returning TRUE means that we handled the method invocation */
2217 }
2218
2219 /* ---------------------------------------------------------------------------------------------------- */
2220
2221 typedef struct
2222 {
2223 UDisksObject *object;
2224 const gchar *type;
2225 } FormatWaitData;
2226
2227 /* ---------------------------------------------------------------------------------------------------- */
2228
2229 static UDisksObject *
wait_for_filesystem(UDisksDaemon * daemon,gpointer user_data)2230 wait_for_filesystem (UDisksDaemon *daemon,
2231 gpointer user_data)
2232 {
2233 FormatWaitData *data = user_data;
2234 UDisksObject *ret = NULL;
2235 UDisksBlock *block = NULL;
2236 UDisksPartitionTable *partition_table = NULL;
2237 UDisksFilesystem *filesystem = NULL;
2238 gchar *id_type = NULL;
2239 gchar *partition_table_type = NULL;
2240
2241 block = udisks_object_get_block (data->object);
2242 if (block == NULL)
2243 goto out;
2244
2245 partition_table = udisks_object_get_partition_table (data->object);
2246 filesystem = udisks_object_get_filesystem (data->object);
2247
2248 id_type = udisks_block_dup_id_type (block);
2249
2250 if (g_strcmp0 (data->type, "empty") == 0)
2251 {
2252 if ((id_type == NULL || g_strcmp0 (id_type, "") == 0 ||
2253 g_strcmp0 (id_type, "crypto_unknown") == 0) && partition_table == NULL)
2254 {
2255 ret = g_object_ref (data->object);
2256 goto out;
2257 }
2258 }
2259
2260 if (g_strcmp0 (id_type, data->type) == 0)
2261 {
2262 /* check that we should expect a filesystem and wait for corresponding interface
2263 * to be exported on the object */
2264 if (g_strcmp0 (data->type, "empty") == 0 ||
2265 ! udisks_linux_block_object_contains_filesystem (data->object) ||
2266 filesystem != NULL)
2267 {
2268 ret = g_object_ref (data->object);
2269 goto out;
2270 }
2271 }
2272
2273 if (partition_table != NULL)
2274 {
2275 partition_table_type = udisks_partition_table_dup_type_ (partition_table);
2276 if (g_strcmp0 (partition_table_type, data->type) == 0)
2277 {
2278 ret = g_object_ref (data->object);
2279 goto out;
2280 }
2281 }
2282
2283 out:
2284 g_free (partition_table_type);
2285 g_free (id_type);
2286 g_clear_object (&partition_table);
2287 g_clear_object (&filesystem);
2288 g_clear_object (&block);
2289 return ret;
2290 }
2291
2292 /* ---------------------------------------------------------------------------------------------------- */
2293
2294 static UDisksObject *
wait_for_luks_uuid(UDisksDaemon * daemon,gpointer user_data)2295 wait_for_luks_uuid (UDisksDaemon *daemon,
2296 gpointer user_data)
2297 {
2298 FormatWaitData *data = user_data;
2299 UDisksObject *ret = NULL;
2300 UDisksBlock *block = NULL;
2301
2302 block = udisks_object_get_block (data->object);
2303 if (block == NULL)
2304 goto out;
2305
2306 if (g_strcmp0 (udisks_block_get_id_type (block), "crypto_LUKS") != 0)
2307 goto out;
2308
2309 ret = g_object_ref (data->object);
2310
2311 out:
2312 g_clear_object (&block);
2313 return ret;
2314 }
2315
2316 /* ---------------------------------------------------------------------------------------------------- */
2317
2318 static UDisksObject *
wait_for_luks_cleartext(UDisksDaemon * daemon,gpointer user_data)2319 wait_for_luks_cleartext (UDisksDaemon *daemon,
2320 gpointer user_data)
2321 {
2322 FormatWaitData *data = user_data;
2323 UDisksObject *ret = NULL;
2324 GList *objects, *l;
2325
2326 objects = udisks_daemon_get_objects (daemon);
2327 for (l = objects; l != NULL; l = l->next)
2328 {
2329 UDisksObject *object = UDISKS_OBJECT (l->data);
2330 UDisksBlock *block = NULL;
2331
2332 block = udisks_object_get_block (object);
2333 if (block != NULL)
2334 {
2335 if (g_strcmp0 (udisks_block_get_crypto_backing_device (block),
2336 g_dbus_object_get_object_path (G_DBUS_OBJECT (data->object))) == 0)
2337 {
2338 g_object_unref (block);
2339 ret = g_object_ref (object);
2340 goto out;
2341 }
2342 g_object_unref (block);
2343 }
2344 }
2345
2346 out:
2347 g_list_free_full (objects, g_object_unref);
2348 return ret;
2349 }
2350
2351 /* ---------------------------------------------------------------------------------------------------- */
2352
2353 static gboolean
erase_ata_device(UDisksBlock * block,UDisksObject * object,UDisksDaemon * daemon,uid_t caller_uid,gboolean enhanced,GError ** error)2354 erase_ata_device (UDisksBlock *block,
2355 UDisksObject *object,
2356 UDisksDaemon *daemon,
2357 uid_t caller_uid,
2358 gboolean enhanced,
2359 GError **error)
2360 {
2361 gboolean ret = FALSE;
2362 UDisksObject *drive_object = NULL;
2363 UDisksDriveAta *ata = NULL;
2364
2365 drive_object = udisks_daemon_find_object (daemon, udisks_block_get_drive (block));
2366 if (drive_object == NULL)
2367 {
2368 g_set_error (error, UDISKS_ERROR, UDISKS_ERROR_FAILED, "No drive object");
2369 goto out;
2370 }
2371 ata = udisks_object_get_drive_ata (drive_object);
2372 if (ata == NULL)
2373 {
2374 g_set_error (error, UDISKS_ERROR, UDISKS_ERROR_FAILED, "Drive is not an ATA drive");
2375 goto out;
2376 }
2377
2378 /* sleep a tiny bit here to avoid the secure erase code racing with
2379 * programs spawned by udev
2380 */
2381 g_usleep (500 * 1000);
2382
2383 ret = udisks_linux_drive_ata_secure_erase_sync (UDISKS_LINUX_DRIVE_ATA (ata),
2384 caller_uid,
2385 enhanced,
2386 error);
2387
2388 out:
2389 g_clear_object (&ata);
2390 g_clear_object (&drive_object);
2391 return ret;
2392 }
2393
2394 /* ---------------------------------------------------------------------------------------------------- */
2395
2396 #define ERASE_SIZE (1 * 1024*1024)
2397
2398 static gboolean
erase_device(UDisksBlock * block,UDisksObject * object,UDisksDaemon * daemon,uid_t caller_uid,const gchar * erase_type,GError ** error)2399 erase_device (UDisksBlock *block,
2400 UDisksObject *object,
2401 UDisksDaemon *daemon,
2402 uid_t caller_uid,
2403 const gchar *erase_type,
2404 GError **error)
2405 {
2406 gboolean ret = FALSE;
2407 const gchar *device_file = NULL;
2408 UDisksBaseJob *job = NULL;
2409 gint fd = -1;
2410 guint64 size;
2411 guint64 pos;
2412 guchar *buf = NULL;
2413 gint64 time_of_last_signal;
2414 GError *local_error = NULL;
2415
2416 if (g_strcmp0 (erase_type, "ata-secure-erase") == 0)
2417 {
2418 ret = erase_ata_device (block, object, daemon, caller_uid, FALSE, error);
2419 goto out;
2420 }
2421 else if (g_strcmp0 (erase_type, "ata-secure-erase-enhanced") == 0)
2422 {
2423 ret = erase_ata_device (block, object, daemon, caller_uid, TRUE, error);
2424 goto out;
2425 }
2426 else if (g_strcmp0 (erase_type, "zero") != 0)
2427 {
2428 g_set_error (&local_error, UDISKS_ERROR, UDISKS_ERROR_FAILED,
2429 "Unknown or unsupported erase type `%s'",
2430 erase_type);
2431 goto out;
2432 }
2433
2434 device_file = udisks_block_get_device (block);
2435 fd = open (device_file, O_WRONLY | O_SYNC | O_EXCL);
2436 if (fd == -1)
2437 {
2438 g_set_error (&local_error, UDISKS_ERROR, UDISKS_ERROR_FAILED,
2439 "Error opening device %s for erase: %m", device_file);
2440 goto out;
2441 }
2442
2443 job = udisks_daemon_launch_simple_job (daemon, object, "format-erase", caller_uid, NULL);
2444 udisks_base_job_set_auto_estimate (UDISKS_BASE_JOB (job), TRUE);
2445 udisks_job_set_progress_valid (UDISKS_JOB (job), TRUE);
2446
2447 if (ioctl (fd, BLKGETSIZE64, &size) != 0)
2448 {
2449 g_set_error (&local_error, UDISKS_ERROR, UDISKS_ERROR_FAILED,
2450 "Error doing BLKGETSIZE64 iotctl on %s: %m", device_file);
2451 goto out;
2452 }
2453
2454 udisks_job_set_bytes (UDISKS_JOB (job), size);
2455
2456 buf = g_new0 (guchar, ERASE_SIZE);
2457 pos = 0;
2458 time_of_last_signal = g_get_monotonic_time ();
2459 while (pos < size)
2460 {
2461 size_t to_write;
2462 ssize_t num_written;
2463 gint64 now;
2464
2465 to_write = MIN (size - pos, ERASE_SIZE);
2466 again:
2467 num_written = write (fd, buf, to_write);
2468 if (num_written == -1 || num_written == 0)
2469 {
2470 if (errno == EINTR)
2471 goto again;
2472 g_set_error (&local_error, UDISKS_ERROR, UDISKS_ERROR_FAILED,
2473 "Error writing %d bytes to %s: %m",
2474 (gint) to_write, device_file);
2475 goto out;
2476 }
2477 pos += num_written;
2478
2479 if (g_cancellable_is_cancelled (udisks_base_job_get_cancellable (job)))
2480 {
2481 g_set_error (&local_error, UDISKS_ERROR, UDISKS_ERROR_CANCELLED,
2482 "Job was canceled");
2483 goto out;
2484 }
2485
2486 /* only emit D-Bus signal at most once a second */
2487 now = g_get_monotonic_time ();
2488 if (now - time_of_last_signal > G_USEC_PER_SEC)
2489 {
2490 /* TODO: estimation etc. */
2491 udisks_job_set_progress (UDISKS_JOB (job), ((gdouble) pos) / size);
2492 time_of_last_signal = now;
2493 }
2494 }
2495
2496 ret = TRUE;
2497
2498 out:
2499 if (job != NULL)
2500 {
2501 if (local_error != NULL)
2502 udisks_simple_job_complete (UDISKS_SIMPLE_JOB (job), FALSE, local_error->message);
2503 else
2504 udisks_simple_job_complete (UDISKS_SIMPLE_JOB (job), TRUE, "");
2505 }
2506 if (local_error != NULL)
2507 g_propagate_error (error, local_error);
2508 g_free (buf);
2509 if (fd != -1)
2510 close (fd);
2511 return ret;
2512 }
2513
2514 /* ---------------------------------------------------------------------------------------------------- */
2515
2516 static const struct
2517 {
2518 const gchar *table_type;
2519 const gchar *id_type;
2520 const gchar *partition_type;
2521 } partition_types_by_id[] = {
2522 {"dos", "vfat", "0x0c"},
2523 {"dos", "ntfs", "0x07"},
2524 {"dos", "exfat", "0x07"},
2525 {"dos", "swap", "0x82"},
2526 {"dos", "ext2", "0x83"},
2527 {"dos", "ext3", "0x83"},
2528 {"dos", "ext4", "0x83"},
2529 {"dos", "xfs", "0x83"},
2530 {"dos", "btrfs", "0x83"},
2531 {"dos", "crypto_LUKS", "0xe8"},
2532 {"dos", "udf", "0x07"},
2533
2534 {"gpt", "vfat", "ebd0a0a2-b9e5-4433-87c0-68b6b72699c7"}, /* Microsoft Basic Data */
2535 {"gpt", "ntfs", "ebd0a0a2-b9e5-4433-87c0-68b6b72699c7"},
2536 {"gpt", "exfat", "ebd0a0a2-b9e5-4433-87c0-68b6b72699c7"},
2537 {"gpt", "swap", "0657fd6d-a4ab-43c4-84e5-0933c84b4f4f"}, /* Linux Swap */
2538 {"gpt", "ext2", "0fc63daf-8483-4772-8e79-3d69d8477de4"}, /* Linux Filesystem */
2539 {"gpt", "ext3", "0fc63daf-8483-4772-8e79-3d69d8477de4"},
2540 {"gpt", "ext4", "0fc63daf-8483-4772-8e79-3d69d8477de4"},
2541 {"gpt", "xfs", "0fc63daf-8483-4772-8e79-3d69d8477de4"},
2542 {"gpt", "btrfs", "0fc63daf-8483-4772-8e79-3d69d8477de4"},
2543 {"gpt", "crypto_LUKS", "ca7d7ccb-63ed-4c53-861c-1742536059cc"},
2544 {"gpt", "udf", "ebd0a0a2-b9e5-4433-87c0-68b6b72699c7"},
2545 };
2546
2547
2548 /* may return NULL if nothing suitable was found */
2549 static const gchar *
determine_partition_type_for_id(const gchar * table_type,const gchar * id_type)2550 determine_partition_type_for_id (const gchar *table_type,
2551 const gchar *id_type)
2552 {
2553 const gchar *ret = NULL;
2554 guint n;
2555
2556 for (n = 0; n < G_N_ELEMENTS (partition_types_by_id); n++)
2557 {
2558 if (g_strcmp0 (partition_types_by_id[n].table_type, table_type) == 0 &&
2559 g_strcmp0 (partition_types_by_id[n].id_type, id_type) == 0)
2560 {
2561 ret = partition_types_by_id[n].partition_type;
2562 goto out;
2563 }
2564 }
2565 out:
2566 return ret;
2567 }
2568
2569 /* ---------------------------------------------------------------------------------------------------- */
2570
2571 typedef gboolean BlockWalker (UDisksDaemon *daemon,
2572 UDisksBlock *block,
2573 gboolean is_leaf,
2574 gpointer user_data,
2575 GError **error);
2576
2577 static UDisksPartitionTable *
peek_partition_table(UDisksDaemon * daemon,UDisksPartition * partition)2578 peek_partition_table (UDisksDaemon *daemon,
2579 UDisksPartition *partition)
2580 {
2581 UDisksObject *object;
2582 UDisksPartitionTable *pt;
2583
2584 object = udisks_daemon_find_object (daemon, udisks_partition_get_table (partition));
2585 pt = object ? udisks_object_peek_partition_table (object) : NULL;
2586
2587 g_clear_object (&object);
2588 return pt;
2589 }
2590
2591 static UDisksBlock *
get_cleartext_block(UDisksDaemon * daemon,UDisksBlock * block)2592 get_cleartext_block (UDisksDaemon *daemon,
2593 UDisksBlock *block)
2594 {
2595 UDisksBlock *ret = NULL;
2596 GDBusObject *object;
2597 const gchar *object_path;
2598 GList *objects = NULL;
2599 GList *l;
2600
2601 object = g_dbus_interface_get_object (G_DBUS_INTERFACE (block));
2602 if (object == NULL)
2603 goto out;
2604
2605 object_path = g_dbus_object_get_object_path (object);
2606 objects = udisks_daemon_get_objects (daemon);
2607 for (l = objects; l != NULL; l = l->next)
2608 {
2609 UDisksObject *iter_object = UDISKS_OBJECT (l->data);
2610 UDisksBlock *iter_block;
2611
2612 iter_block = udisks_object_peek_block (iter_object);
2613 if (iter_block == NULL)
2614 continue;
2615
2616 if (g_strcmp0 (udisks_block_get_crypto_backing_device (iter_block), object_path) == 0)
2617 {
2618 ret = g_object_ref (iter_block);
2619 goto out;
2620 }
2621 }
2622
2623 out:
2624 g_list_free_full (objects, g_object_unref);
2625 return ret;
2626 }
2627
2628 static gboolean
walk_block(UDisksDaemon * daemon,UDisksBlock * block,BlockWalker * walker,gpointer user_data,GError ** error)2629 walk_block (UDisksDaemon *daemon,
2630 UDisksBlock *block,
2631 BlockWalker *walker,
2632 gpointer user_data,
2633 GError **error)
2634 {
2635 UDisksObject *object;
2636 UDisksBlock *cleartext;
2637 gboolean is_leaf = TRUE;
2638 guint num_parts = 0;
2639
2640 object = UDISKS_OBJECT (g_dbus_interface_get_object (G_DBUS_INTERFACE (block)));
2641 if (object != NULL)
2642 {
2643 /* Recurse for all primary and extended partitions if this is a
2644 * partition table, or for all logical partitions if this is a
2645 * extended partition. */
2646
2647 UDisksPartitionTable *table;
2648 gboolean is_container;
2649
2650 UDisksPartition *partition = udisks_object_peek_partition (object);
2651 if (partition && udisks_partition_get_is_container (partition))
2652 {
2653 table = peek_partition_table (daemon, partition);
2654 is_container = TRUE;
2655 }
2656 else
2657 {
2658 table = udisks_object_peek_partition_table (object);
2659 is_container = FALSE;
2660 }
2661
2662 if (table)
2663 {
2664 GList *ps, *l;
2665 ps = udisks_linux_partition_table_get_partitions (daemon, table, &num_parts);
2666 for (l = ps; l != NULL; l = l->next)
2667 {
2668 UDisksPartition *p = UDISKS_PARTITION (l->data);
2669 UDisksObject *o = (UDisksObject *) g_dbus_interface_get_object (G_DBUS_INTERFACE (p));
2670 UDisksBlock *b = o ? udisks_object_peek_block (o) : NULL;
2671 if (b && !is_container == !udisks_partition_get_is_contained (p))
2672 {
2673 is_leaf = FALSE;
2674 if (!walk_block (daemon, b, walker, user_data, error))
2675 {
2676 g_list_free_full (ps, g_object_unref);
2677 return FALSE;
2678 }
2679 }
2680 }
2681 g_list_free_full (ps, g_object_unref);
2682 }
2683 }
2684
2685 cleartext = get_cleartext_block (daemon, block);
2686 if (cleartext)
2687 {
2688 is_leaf = FALSE;
2689 if (!walk_block (daemon, cleartext, walker, user_data, error))
2690 {
2691 g_object_unref (cleartext);
2692 return FALSE;
2693 }
2694 g_object_unref (cleartext);
2695 }
2696
2697 return walker (daemon, block, is_leaf, user_data, error);
2698 }
2699
2700 gboolean
udisks_linux_remove_configuration(GVariant * config,GError ** error)2701 udisks_linux_remove_configuration (GVariant *config,
2702 GError **error)
2703 {
2704 GVariantIter iter;
2705 const gchar *item_type;
2706 GVariant *details;
2707
2708 udisks_debug ("Removing for teardown: %s", g_variant_print (config, FALSE));
2709
2710 g_variant_iter_init (&iter, config);
2711 while (g_variant_iter_next (&iter, "(&s@a{sv})", &item_type, &details))
2712 {
2713 if (strcmp (item_type, "fstab") == 0)
2714 {
2715 if (!add_remove_fstab_entry (NULL, details, NULL, error))
2716 {
2717 g_variant_unref (details);
2718 return FALSE;
2719 }
2720 }
2721 else if (strcmp (item_type, "crypttab") == 0)
2722 {
2723 if (!add_remove_crypttab_entry (NULL, details, NULL, error))
2724 {
2725 g_variant_unref (details);
2726 return FALSE;
2727 }
2728 }
2729 g_variant_unref (details);
2730 }
2731
2732 return TRUE;
2733 }
2734
2735 struct TeardownData {
2736 GDBusMethodInvocation *invocation;
2737 GVariant *options;
2738 };
2739
2740 static gboolean
teardown_block_walker(UDisksDaemon * daemon,UDisksBlock * block,gboolean is_leaf,gpointer user_data,GError ** error)2741 teardown_block_walker (UDisksDaemon *daemon,
2742 UDisksBlock *block,
2743 gboolean is_leaf,
2744 gpointer user_data,
2745 GError **error)
2746 {
2747 struct TeardownData *data = user_data;
2748 UDisksObject *object = UDISKS_OBJECT (g_dbus_interface_get_object (G_DBUS_INTERFACE (block)));
2749 UDisksEncrypted *enc = udisks_object_peek_encrypted (object);
2750
2751 if (enc)
2752 {
2753 UDisksBlock *cleartext = get_cleartext_block (daemon, block);
2754 if (cleartext)
2755 {
2756 /* The crypto backing device is unlocked and the cleartext
2757 device has been cleaned up. Lock the backing device so
2758 that we can format or wipe it later.
2759 */
2760 if (enc && !udisks_linux_encrypted_lock (UDISKS_LINUX_ENCRYPTED (enc),
2761 data->invocation,
2762 data->options,
2763 error))
2764 return FALSE;
2765 }
2766 else
2767 {
2768 /* The crypto backing device is locked and the cleartext
2769 device has not been cleaned up (since it doesn't exist).
2770 Remove its child configuration.
2771 */
2772 if (!udisks_linux_remove_configuration (udisks_encrypted_get_child_configuration (enc), error))
2773 return FALSE;
2774 }
2775 }
2776
2777 return udisks_linux_remove_configuration (udisks_block_get_configuration (block), error);
2778 }
2779
2780 gboolean
udisks_linux_block_teardown(UDisksBlock * block,GDBusMethodInvocation * invocation,GVariant * options,GError ** error)2781 udisks_linux_block_teardown (UDisksBlock *block,
2782 GDBusMethodInvocation *invocation,
2783 GVariant *options,
2784 GError **error)
2785 {
2786 UDisksObject *object = UDISKS_OBJECT (g_dbus_interface_get_object (G_DBUS_INTERFACE (block)));
2787 UDisksDaemon *daemon = udisks_linux_block_object_get_daemon (UDISKS_LINUX_BLOCK_OBJECT (object));
2788 struct TeardownData data;
2789
2790 data.invocation = invocation;
2791 data.options = options;
2792 return walk_block (daemon, block, teardown_block_walker, &data, error);
2793 }
2794
2795 /* ---------------------------------------------------------------------------------------------------- */
2796
2797 gboolean
udisks_linux_block_is_luks(UDisksBlock * block)2798 udisks_linux_block_is_luks (UDisksBlock *block)
2799 {
2800 return g_strcmp0 (udisks_block_get_id_usage (block), "crypto") == 0 &&
2801 g_strcmp0 (udisks_block_get_id_type (block), "crypto_LUKS") == 0;
2802 }
2803
2804 gboolean
udisks_linux_block_is_tcrypt(UDisksBlock * block)2805 udisks_linux_block_is_tcrypt (UDisksBlock *block)
2806 {
2807 return g_strcmp0 (udisks_block_get_id_usage (block), "crypto") == 0 &&
2808 g_strcmp0 (udisks_block_get_id_type (block), "crypto_TCRYPT") == 0;
2809 }
2810
2811 gboolean
udisks_linux_block_is_bitlk(UDisksBlock * block)2812 udisks_linux_block_is_bitlk (UDisksBlock *block)
2813 {
2814 return g_strcmp0 (udisks_block_get_id_usage (block), "crypto") == 0 &&
2815 g_strcmp0 (udisks_block_get_id_type (block), "BitLocker") == 0;
2816 }
2817
2818 gboolean
udisks_linux_block_is_unknown_crypto(UDisksBlock * block)2819 udisks_linux_block_is_unknown_crypto (UDisksBlock *block)
2820 {
2821 return g_strcmp0 (udisks_block_get_id_usage (block), "crypto") == 0 &&
2822 g_strcmp0 (udisks_block_get_id_type (block), "crypto_unknown") == 0;
2823 }
2824
2825 /* ---------------------------------------------------------------------------------------------------- */
2826
2827 void
udisks_linux_block_encrypted_lock(UDisksBlock * block)2828 udisks_linux_block_encrypted_lock (UDisksBlock *block)
2829 {
2830 UDisksLinuxBlock *block_iface = UDISKS_LINUX_BLOCK (block);
2831 g_mutex_lock (&block_iface->encrypted_lock);
2832 }
2833
2834 void
udisks_linux_block_encrypted_unlock(UDisksBlock * block)2835 udisks_linux_block_encrypted_unlock (UDisksBlock *block)
2836 {
2837 UDisksLinuxBlock *block_iface = UDISKS_LINUX_BLOCK (block);
2838 g_mutex_unlock (&block_iface->encrypted_lock);
2839 }
2840
2841 /* ---------------------------------------------------------------------------------------------------- */
2842
2843 static void
handle_format_failure(GDBusMethodInvocation * invocation,GError * error)2844 handle_format_failure (GDBusMethodInvocation *invocation,
2845 GError *error)
2846 {
2847 udisks_warning ("%s", error->message);
2848 if (invocation != NULL)
2849 g_dbus_method_invocation_take_error (invocation, error);
2850 else
2851 g_clear_error (&error);
2852 }
2853
2854 static gboolean
add_blocksize(gchar ** command,const gchar * device,GError ** error)2855 add_blocksize (gchar **command,
2856 const gchar *device,
2857 GError **error)
2858 {
2859 gint fd = -1;
2860 gchar *new_cmd = NULL;
2861 gint blksize = 0;
2862 gchar *size_str = NULL;
2863
2864 fd = open (device, O_RDONLY);
2865 if (fd < 0)
2866 {
2867 g_set_error (error, UDISKS_ERROR, UDISKS_ERROR_FAILED,
2868 "Failed to open the device '%s' to get its block size", device);
2869 return FALSE;
2870 }
2871
2872 if (ioctl (fd, BLKSSZGET, &blksize) < 0)
2873 {
2874 g_set_error (error, UDISKS_ERROR, UDISKS_ERROR_FAILED,
2875 "Failed to get block size of the device '%s'", device);
2876 close (fd);
2877 return FALSE;
2878 }
2879 close (fd);
2880
2881 size_str = g_strdup_printf ("%d", blksize);
2882 new_cmd = udisks_daemon_util_subst_str_and_escape (*command, "$BLOCKSIZE", size_str);
2883 g_free (size_str);
2884 g_free (*command);
2885 *command = new_cmd;
2886
2887 return TRUE;
2888 }
2889
2890 static gchar *
build_command(const gchar * template,const gchar * device,const gchar * label,const gchar * options,GError ** error)2891 build_command (const gchar *template,
2892 const gchar *device,
2893 const gchar *label,
2894 const gchar *options,
2895 GError **error)
2896 {
2897 gchar *tmp, *tmp2, *command;
2898 tmp = udisks_daemon_util_subst_str_and_escape (template, "$DEVICE", device);
2899 tmp2 = udisks_daemon_util_subst_str_and_escape (tmp, "$LABEL", label != NULL ? label : "");
2900 command = udisks_daemon_util_subst_str (tmp2, "$OPTIONS", options != NULL ? options : "");
2901 g_free (tmp);
2902 g_free (tmp2);
2903 if (strstr (command, "$BLOCKSIZE") && ! add_blocksize (&command, device, error))
2904 {
2905 g_free (command);
2906 return NULL;
2907 }
2908
2909 return command;
2910 }
2911
2912 static inline gboolean
need_partprobe_after_mkfs(const gchar * fs_type)2913 need_partprobe_after_mkfs (const gchar *fs_type)
2914 {
2915 /* udftools makes fake MBR since the 2.0 release */
2916 return (g_strcmp0 (fs_type, "udf") == 0);
2917 }
2918
2919 void
udisks_linux_block_handle_format(UDisksBlock * block,GDBusMethodInvocation * invocation,const gchar * type,GVariant * options,void (* complete)(gpointer user_data),gpointer complete_user_data)2920 udisks_linux_block_handle_format (UDisksBlock *block,
2921 GDBusMethodInvocation *invocation,
2922 const gchar *type,
2923 GVariant *options,
2924 void (*complete)(gpointer user_data),
2925 gpointer complete_user_data)
2926 {
2927 FormatWaitData *wait_data = NULL;
2928 UDisksObject *object;
2929 UDisksPartition *partition = NULL;
2930 UDisksPartitionTable *partition_table = NULL;
2931 UDisksObject *cleartext_object = NULL;
2932 UDisksBlock *cleartext_block = NULL;
2933 UDisksLinuxDevice *udev_cleartext_device = NULL;
2934 UDisksBlock *block_to_mkfs = NULL;
2935 UDisksObject *object_to_mkfs = NULL;
2936 UDisksDaemon *daemon;
2937 UDisksState *state = NULL;
2938 UDisksConfigManager *config_manager = NULL;
2939 const gchar *action_id;
2940 const gchar *message;
2941 const FSInfo *fs_info;
2942 const gchar *command_options = NULL;
2943 gchar *command = NULL;
2944 gchar *error_message;
2945 GError *error;
2946 int status;
2947 uid_t caller_uid;
2948 gid_t caller_gid;
2949 gboolean take_ownership = FALSE;
2950 GString *encrypt_passphrase = NULL;
2951 gchar *encrypt_type = NULL;
2952 gchar *erase_type = NULL;
2953 gchar *mapped_name = NULL;
2954 const gchar *label = NULL;
2955 gchar *device_name = NULL;
2956 gboolean was_partitioned = FALSE;
2957 gboolean no_block = FALSE;
2958 gboolean update_partition_type = FALSE;
2959 gboolean dry_run_first = FALSE;
2960 const gchar *partition_type = NULL;
2961 GVariant *config_items = NULL;
2962 gboolean teardown_flag = FALSE;
2963 gboolean no_discard_flag = FALSE;
2964 BDPartTableType part_table_type = BD_PART_TABLE_UNDEF;
2965 UDisksObject *filesystem_object;
2966
2967 error = NULL;
2968 object = udisks_daemon_util_dup_object (block, &error);
2969 if (object == NULL)
2970 {
2971 g_dbus_method_invocation_take_error (invocation, error);
2972 goto out;
2973 }
2974
2975 daemon = udisks_linux_block_object_get_daemon (UDISKS_LINUX_BLOCK_OBJECT (object));
2976 state = udisks_daemon_get_state (daemon);
2977 config_manager = udisks_daemon_get_config_manager (daemon);
2978 command = NULL;
2979 error_message = NULL;
2980
2981 udisks_linux_block_object_lock_for_cleanup (UDISKS_LINUX_BLOCK_OBJECT (object));
2982 udisks_state_check_block (state, udisks_linux_block_object_get_device_number (UDISKS_LINUX_BLOCK_OBJECT (object)));
2983
2984 g_variant_lookup (options, "take-ownership", "b", &take_ownership);
2985 udisks_variant_lookup_binary (options, "encrypt.passphrase", &encrypt_passphrase);
2986 g_variant_lookup (options, "encrypt.type", "s", &encrypt_type);
2987 g_variant_lookup (options, "erase", "s", &erase_type);
2988 g_variant_lookup (options, "no-block", "b", &no_block);
2989 g_variant_lookup (options, "update-partition-type", "b", &update_partition_type);
2990 g_variant_lookup (options, "dry-run-first", "b", &dry_run_first);
2991 g_variant_lookup (options, "config-items", "@a(sa{sv})", &config_items);
2992 g_variant_lookup (options, "tear-down", "b", &teardown_flag);
2993 g_variant_lookup (options, "no-discard", "b", &no_discard_flag);
2994 g_variant_lookup (options, "label", "&s", &label);
2995
2996 partition = udisks_object_get_partition (object);
2997 if (partition != NULL)
2998 {
2999 UDisksObject *partition_table_object;
3000
3001 /* Fail if partition contains a partition table (e.g. Fedora Hybrid ISO).
3002 * See: https://bugs.freedesktop.org/show_bug.cgi?id=76178
3003 */
3004 if (udisks_partition_get_offset (partition) == 0)
3005 {
3006 g_dbus_method_invocation_return_error (invocation,
3007 UDISKS_ERROR,
3008 UDISKS_ERROR_NOT_SUPPORTED,
3009 "This partition cannot be modified because it contains a partition table; please reinitialize layout of the whole device.");
3010 goto out;
3011 }
3012
3013 partition_table_object = udisks_daemon_find_object (daemon, udisks_partition_get_table (partition));
3014 if (partition_table_object == NULL)
3015 {
3016 g_clear_object (&partition);
3017 }
3018 else
3019 {
3020 partition_table = udisks_object_get_partition_table (partition_table_object);
3021 g_clear_object (&partition_table_object);
3022 }
3023 }
3024 /* figure out partition type to set, if requested */
3025 if (update_partition_type && partition != NULL && partition_table != NULL)
3026 {
3027 partition_type = determine_partition_type_for_id (udisks_partition_table_get_type_ (partition_table),
3028 encrypt_passphrase != NULL ? "crypto_LUKS" : type);
3029 }
3030
3031 if (!udisks_daemon_util_get_caller_uid_sync (daemon, invocation, NULL /* GCancellable */, &caller_uid, &error))
3032 {
3033 g_dbus_method_invocation_take_error (invocation, error);
3034 goto out;
3035 }
3036
3037 if (!udisks_daemon_util_get_user_info (caller_uid, &caller_gid, NULL /* user name */, &error))
3038 {
3039 g_dbus_method_invocation_take_error (invocation, error);
3040 goto out;
3041 }
3042
3043 if (g_strcmp0 (erase_type, "ata-secure-erase") == 0 ||
3044 g_strcmp0 (erase_type, "ata-secure-erase-enhanced") == 0)
3045 {
3046 /* Translators: Shown in authentication dialog when the user
3047 * requests erasing a hard disk using the SECURE ERASE UNIT
3048 * command.
3049 *
3050 * Do not translate $(drive), it's a placeholder and
3051 * will be replaced by the name of the drive/device in question
3052 */
3053 message = N_("Authentication is required to perform a secure erase of $(drive)");
3054 action_id = "org.freedesktop.udisks2.ata-secure-erase";
3055 }
3056 else
3057 {
3058 /* Translators: Shown in authentication dialog when formatting a
3059 * device. This includes both creating a filesystem or partition
3060 * table.
3061 *
3062 * Do not translate $(drive), it's a placeholder and will
3063 * be replaced by the name of the drive/device in question
3064 */
3065 message = N_("Authentication is required to format $(drive)");
3066 action_id = "org.freedesktop.udisks2.modify-device";
3067 if (!udisks_daemon_util_setup_by_user (daemon, object, caller_uid))
3068 {
3069 if (udisks_block_get_hint_system (block))
3070 {
3071 action_id = "org.freedesktop.udisks2.modify-device-system";
3072 }
3073 else if (!udisks_daemon_util_on_user_seat (daemon, object, caller_uid))
3074 {
3075 action_id = "org.freedesktop.udisks2.modify-device-other-seat";
3076 }
3077 }
3078 }
3079
3080 /* TODO: Consider just accepting any @type and just running "mkfs -t <type>".
3081 * There are some obvious security implications by doing this, though
3082 */
3083 fs_info = get_fs_info (type);
3084 if (fs_info == NULL || fs_info->command_create_fs == NULL)
3085 {
3086 g_dbus_method_invocation_return_error (invocation,
3087 UDISKS_ERROR,
3088 UDISKS_ERROR_NOT_SUPPORTED,
3089 "Creation of file system type %s is not supported",
3090 type);
3091 goto out;
3092 }
3093
3094 if (!udisks_daemon_util_check_authorization_sync (daemon,
3095 object,
3096 action_id,
3097 options,
3098 message,
3099 invocation))
3100 goto out;
3101
3102 if ((config_items != NULL || teardown_flag) &&
3103 !udisks_daemon_util_check_authorization_sync (daemon,
3104 NULL,
3105 "org.freedesktop.udisks2.modify-system-configuration",
3106 options,
3107 N_("Authentication is required to modify the system configuration"),
3108 invocation))
3109 goto out;
3110
3111 was_partitioned = (udisks_object_peek_partition_table (object) != NULL);
3112
3113 if (teardown_flag)
3114 {
3115 if (!udisks_linux_block_teardown (block, invocation, options, &error))
3116 {
3117 g_dbus_method_invocation_take_error (invocation, error);
3118 goto out;
3119 }
3120 }
3121
3122 device_name = udisks_block_dup_device (block);
3123
3124 /* First wipe the device... */
3125 if (! bd_fs_wipe (device_name, TRUE, &error))
3126 {
3127 if (g_error_matches (error, BD_FS_ERROR, BD_FS_ERROR_NOFS))
3128 /* no signature to remove, ignore */
3129 g_clear_error (&error);
3130 else
3131 {
3132 g_dbus_method_invocation_return_error (invocation,
3133 UDISKS_ERROR,
3134 UDISKS_ERROR_FAILED,
3135 "Error wiping device: %s",
3136 error->message);
3137 g_clear_error (&error);
3138 goto out;
3139 }
3140 }
3141
3142 /* ...then wait until this change has taken effect */
3143 if (was_partitioned)
3144 udisks_linux_block_object_reread_partition_table (UDISKS_LINUX_BLOCK_OBJECT (object));
3145 udisks_linux_block_object_trigger_uevent_sync (UDISKS_LINUX_BLOCK_OBJECT (object),
3146 UDISKS_DEFAULT_WAIT_TIMEOUT);
3147 wait_data = g_new0 (FormatWaitData, 1);
3148 wait_data->object = object;
3149 wait_data->type = "empty";
3150 filesystem_object = udisks_daemon_wait_for_object_sync (daemon,
3151 wait_for_filesystem,
3152 wait_data,
3153 NULL,
3154 UDISKS_DEFAULT_WAIT_TIMEOUT,
3155 &error);
3156 if (filesystem_object == NULL)
3157 {
3158 g_prefix_error (&error, "Error synchronizing after initial wipe: ");
3159 g_dbus_method_invocation_take_error (invocation, error);
3160 goto out;
3161 }
3162 g_object_unref (filesystem_object);
3163
3164 if (no_discard_flag && fs_info->option_no_discard)
3165 command_options = fs_info->option_no_discard;
3166
3167 /* If requested, check whether the ultimate filesystem creation
3168 will succeed before actually getting to work.
3169 */
3170 if (dry_run_first && fs_info->command_validate_create_fs)
3171 {
3172 const gchar *device = udisks_block_get_device (block);
3173 command = build_command (fs_info->command_validate_create_fs, device, label, command_options, &error);
3174 if (command == NULL)
3175 {
3176 handle_format_failure (invocation, error);
3177 goto out;
3178 }
3179
3180 if (!udisks_daemon_launch_spawned_job_sync (daemon,
3181 object,
3182 "format-mkfs", caller_uid,
3183 NULL, /* cancellable */
3184 0, /* uid_t run_as_uid */
3185 0, /* uid_t run_as_euid */
3186 &status,
3187 &error_message,
3188 NULL, /* input_string */
3189 "%s", command))
3190 {
3191 g_dbus_method_invocation_return_error (invocation,
3192 UDISKS_ERROR,
3193 UDISKS_ERROR_FAILED,
3194 "Error creating file system: %s",
3195 error_message);
3196 g_free (error_message);
3197 goto out;
3198 }
3199
3200 g_free (error_message);
3201 g_free (command);
3202 }
3203
3204 /* And now create the desired filesystem */
3205 wait_data->type = type;
3206
3207 if (encrypt_passphrase != NULL)
3208 {
3209 UDisksObject *luks_uuid_object;
3210 CryptoJobData data;
3211 data.device = device_name;
3212 data.passphrase = encrypt_passphrase;
3213
3214 if (encrypt_type != NULL)
3215 data.type = encrypt_type;
3216 else
3217 data.type = udisks_config_manager_get_encryption (config_manager);
3218
3219 udisks_linux_block_encrypted_lock (block);
3220
3221 /* Create it */
3222 if (!udisks_daemon_launch_threaded_job_sync (daemon,
3223 object,
3224 "format-mkfs",
3225 caller_uid,
3226 luks_format_job_func,
3227 &data,
3228 NULL, /* user_data_free_func */
3229 NULL, /* cancellable */
3230 &error))
3231 {
3232 handle_format_failure (invocation, g_error_new (UDISKS_ERROR, UDISKS_ERROR_FAILED,
3233 "Error creating LUKS device: %s", error->message));
3234 g_clear_error (&error);
3235 udisks_linux_block_encrypted_unlock (block);
3236 goto out;
3237 }
3238 udisks_linux_block_encrypted_unlock (block);
3239
3240 /* Wait for the UUID to be set */
3241 luks_uuid_object = udisks_daemon_wait_for_object_sync (daemon,
3242 wait_for_luks_uuid,
3243 wait_data,
3244 NULL,
3245 UDISKS_DEFAULT_WAIT_TIMEOUT,
3246 &error);
3247 if (luks_uuid_object == NULL)
3248 {
3249 g_prefix_error (&error, "Error waiting for LUKS UUID: ");
3250 handle_format_failure (invocation, error);
3251 goto out;
3252 }
3253 g_object_unref (luks_uuid_object);
3254
3255 /* Open it */
3256 mapped_name = make_block_luksname (block, &error);
3257 if (!mapped_name)
3258 {
3259 g_prefix_error (&error, "Failed to get LUKS UUID: ");
3260 handle_format_failure (invocation, error);
3261 goto out;
3262 }
3263
3264 udisks_linux_block_encrypted_lock (block);
3265 data.map_name = mapped_name;
3266 data.read_only = FALSE;
3267 if (!udisks_daemon_launch_threaded_job_sync (daemon,
3268 object,
3269 "format-mkfs",
3270 caller_uid,
3271 luks_open_job_func,
3272 &data,
3273 NULL, /* user_data_free_func */
3274 NULL, /* cancellable */
3275 &error))
3276 {
3277 handle_format_failure (invocation, g_error_new (UDISKS_ERROR, UDISKS_ERROR_FAILED,
3278 "Error opening LUKS device: %s", error->message));
3279 g_clear_error (&error);
3280 udisks_linux_block_encrypted_unlock (block);
3281 goto out;
3282 }
3283
3284 udisks_linux_block_encrypted_unlock (block);
3285
3286 /* Wait for it */
3287 cleartext_object = udisks_daemon_wait_for_object_sync (daemon,
3288 wait_for_luks_cleartext,
3289 wait_data,
3290 NULL,
3291 UDISKS_DEFAULT_WAIT_TIMEOUT,
3292 &error);
3293 if (cleartext_object == NULL)
3294 {
3295 g_prefix_error (&error, "Error waiting for LUKS cleartext device: ");
3296 handle_format_failure (invocation, error);
3297 goto out;
3298 }
3299 cleartext_block = udisks_object_get_block (cleartext_object);
3300 if (cleartext_block == NULL)
3301 {
3302 handle_format_failure (invocation, g_error_new (UDISKS_ERROR, UDISKS_ERROR_FAILED,
3303 "LUKS cleartext device does not have block interface"));
3304 goto out;
3305 }
3306
3307 /* update the unlocked-crypto-dev file */
3308 udev_cleartext_device = udisks_linux_block_object_get_device (UDISKS_LINUX_BLOCK_OBJECT (cleartext_object));
3309 udisks_state_add_unlocked_crypto_dev (state,
3310 udisks_block_get_device_number (cleartext_block),
3311 udisks_block_get_device_number (block),
3312 g_udev_device_get_sysfs_attr (udev_cleartext_device->udev_device, "dm/uuid"),
3313 caller_uid);
3314
3315 object_to_mkfs = cleartext_object;
3316 block_to_mkfs = cleartext_block;
3317 }
3318 else
3319 {
3320 object_to_mkfs = object;
3321 block_to_mkfs = block;
3322 }
3323
3324 /* complete early, if requested */
3325 if (no_block)
3326 {
3327 complete (complete_user_data);
3328 invocation = NULL;
3329 }
3330
3331 /* Erase the device, if requested
3332 */
3333 if (erase_type != NULL)
3334 {
3335 if (!erase_device (block_to_mkfs, object_to_mkfs, daemon, caller_uid, erase_type, &error))
3336 {
3337 g_prefix_error (&error, "Error erasing device: ");
3338 handle_format_failure (invocation, error);
3339 goto out;
3340 }
3341 }
3342
3343 /* Set label, if needed */
3344 if (label != NULL)
3345 {
3346 /* TODO: return an error if label is too long */
3347 if (strstr (fs_info->command_create_fs, "$LABEL") == NULL)
3348 {
3349 handle_format_failure (invocation, g_error_new (UDISKS_ERROR, UDISKS_ERROR_NOT_SUPPORTED,
3350 "File system type %s does not support labels", type));
3351 goto out;
3352 }
3353 }
3354
3355 if (g_strcmp0 (type, "dos") == 0)
3356 part_table_type = BD_PART_TABLE_MSDOS;
3357 else if (g_strcmp0 (type, "gpt") == 0)
3358 part_table_type = BD_PART_TABLE_GPT;
3359
3360 if (part_table_type == BD_PART_TABLE_UNDEF)
3361 {
3362 /* Build and run mkfs shell command */
3363 const gchar *device = udisks_block_get_device (block_to_mkfs);
3364 command = build_command (fs_info->command_create_fs, device, label, command_options, &error);
3365 if (command == NULL)
3366 {
3367 handle_format_failure (invocation, error);
3368 goto out;
3369 }
3370
3371 if (!udisks_daemon_launch_spawned_job_sync (daemon,
3372 object_to_mkfs,
3373 "format-mkfs", caller_uid,
3374 NULL, /* cancellable */
3375 0, /* uid_t run_as_uid */
3376 0, /* uid_t run_as_euid */
3377 &status,
3378 &error_message,
3379 NULL, /* input_string */
3380 "%s", command))
3381 {
3382 handle_format_failure (invocation, g_error_new (UDISKS_ERROR, UDISKS_ERROR_FAILED,
3383 "Error creating file system: %s", error_message));
3384 g_free (error_message);
3385 goto out;
3386 }
3387 g_free (error_message);
3388 }
3389 else
3390 {
3391 /* Create the partition table. */
3392 if (! bd_part_create_table (device_name, part_table_type, TRUE, &error))
3393 {
3394 handle_format_failure (invocation, error);
3395 goto out;
3396 }
3397 }
3398
3399 /* Set the partition type, if requested */
3400 if (partition_type != NULL && partition != NULL)
3401 {
3402 if (g_strcmp0 (udisks_partition_get_type_ (partition), partition_type) != 0)
3403 {
3404 if (!udisks_linux_partition_set_type_sync (UDISKS_LINUX_PARTITION (partition),
3405 partition_type,
3406 caller_uid,
3407 NULL, /* cancellable */
3408 &error))
3409 {
3410 g_prefix_error (&error, "Error setting partition type after formatting: ");
3411 handle_format_failure (invocation, error);
3412 goto out;
3413 }
3414 }
3415 }
3416
3417 /* The mkfs program may not generate all the uevents we need - so explicitly
3418 * trigger an event here
3419 */
3420 if (need_partprobe_after_mkfs (type))
3421 udisks_linux_block_object_reread_partition_table (UDISKS_LINUX_BLOCK_OBJECT (object));
3422 udisks_linux_block_object_trigger_uevent_sync (UDISKS_LINUX_BLOCK_OBJECT (object_to_mkfs),
3423 UDISKS_DEFAULT_WAIT_TIMEOUT);
3424 wait_data->object = object_to_mkfs;
3425 filesystem_object = udisks_daemon_wait_for_object_sync (daemon,
3426 wait_for_filesystem,
3427 wait_data,
3428 NULL,
3429 UDISKS_DEFAULT_WAIT_TIMEOUT,
3430 &error);
3431 if (filesystem_object == NULL)
3432 {
3433 g_prefix_error (&error,
3434 "Error synchronizing after formatting with type `%s': ",
3435 type);
3436 handle_format_failure (invocation, error);
3437 goto out;
3438 }
3439 g_object_unref (filesystem_object);
3440
3441 /* Change ownership, if requested and supported */
3442 if (take_ownership && fs_info->supports_owners)
3443 {
3444 if (!take_filesystem_ownership (udisks_block_get_device (block_to_mkfs),
3445 type, caller_uid, caller_gid, FALSE, &error))
3446 {
3447 g_prefix_error (&error,
3448 "Failed to take ownership of newly created filesystem: ");
3449 handle_format_failure (invocation, error);
3450 goto out;
3451 }
3452 }
3453
3454 /* Add configuration items */
3455 if (config_items)
3456 {
3457 GVariantIter iter;
3458 const gchar *item_type;
3459 GVariant *details;
3460
3461 g_variant_iter_init (&iter, config_items);
3462 while (g_variant_iter_next (&iter, "(&s@a{sv})", &item_type, &details))
3463 {
3464 if (strcmp (item_type, "fstab") == 0)
3465 {
3466 if (!add_remove_fstab_entry (block_to_mkfs, NULL, details, &error))
3467 {
3468 handle_format_failure (invocation, error);
3469 goto out;
3470 }
3471 }
3472 else if (strcmp (item_type, "crypttab") == 0)
3473 {
3474 if (!add_remove_crypttab_entry (block, NULL, details, &error))
3475 {
3476 handle_format_failure (invocation, error);
3477 goto out;
3478 }
3479 }
3480 g_variant_unref (details);
3481 }
3482 update_configuration (UDISKS_LINUX_BLOCK (block), daemon);
3483 }
3484
3485 if (invocation != NULL)
3486 complete (complete_user_data);
3487
3488 out:
3489 if (object != NULL)
3490 udisks_linux_block_object_release_cleanup_lock (UDISKS_LINUX_BLOCK_OBJECT (object));
3491 if (state != NULL)
3492 udisks_state_check (state);
3493 g_free (device_name);
3494 g_free (mapped_name);
3495 g_free (command);
3496 if (config_items)
3497 g_variant_unref (config_items);
3498 g_free (erase_type);
3499 udisks_string_wipe_and_free (encrypt_passphrase);
3500 g_free (encrypt_type);
3501 g_clear_object (&cleartext_object);
3502 g_clear_object (&cleartext_block);
3503 g_clear_object (&udev_cleartext_device);
3504 g_free (wait_data);
3505 g_clear_object (&partition_table);
3506 g_clear_object (&partition);
3507 g_clear_object (&object);
3508 }
3509
3510 struct FormatCompleteData {
3511 UDisksBlock *block;
3512 GDBusMethodInvocation *invocation;
3513 };
3514
3515 static void
handle_format_complete(gpointer user_data)3516 handle_format_complete (gpointer user_data)
3517 {
3518 struct FormatCompleteData *data = user_data;
3519 udisks_block_complete_format (data->block, data->invocation);
3520 }
3521
3522 static gboolean
handle_format(UDisksBlock * block,GDBusMethodInvocation * invocation,const gchar * type,GVariant * options)3523 handle_format (UDisksBlock *block,
3524 GDBusMethodInvocation *invocation,
3525 const gchar *type,
3526 GVariant *options)
3527 {
3528 struct FormatCompleteData data;
3529 data.block = block;
3530 data.invocation = invocation;
3531 udisks_linux_block_handle_format (block, invocation, type, options,
3532 handle_format_complete, &data);
3533
3534 return TRUE; /* returning true means that we handled the method invocation */
3535 }
3536
3537 /* ---------------------------------------------------------------------------------------------------- */
3538
3539 static gint
open_device(const gchar * device,const gchar * mode,gint flags,GError ** error)3540 open_device (const gchar *device,
3541 const gchar *mode,
3542 gint flags,
3543 GError **error)
3544 {
3545 gint fd = -1;
3546
3547 if (flags & O_RDWR || flags & O_RDONLY || flags & O_WRONLY)
3548 {
3549 g_set_error (error, UDISKS_ERROR, UDISKS_ERROR_FAILED,
3550 "Using 'O_RDWR', 'O_RDONLY' and 'O_WRONLY' flags is not permitted. "
3551 "Use 'mode' argument instead.");
3552 goto out;
3553 }
3554
3555 if (g_strcmp0 (mode, "r") == 0)
3556 flags |= O_RDONLY;
3557 else if (g_strcmp0 (mode, "w") == 0)
3558 flags |= O_WRONLY;
3559 else if (g_strcmp0 (mode, "rw") == 0)
3560 flags |= O_RDWR;
3561 else
3562 {
3563 g_set_error (error, UDISKS_ERROR, UDISKS_ERROR_FAILED,
3564 "Unknown mode '%s'", mode);
3565 goto out;
3566 }
3567
3568 fd = open (device, flags);
3569 if (fd == -1)
3570 {
3571 g_set_error (error, UDISKS_ERROR, UDISKS_ERROR_FAILED,
3572 "Error opening device %s: %m", device);
3573 goto out;
3574 }
3575
3576 out:
3577 return fd;
3578 }
3579
3580 /* ---------------------------------------------------------------------------------------------------- */
3581 static gboolean
handle_open_for_backup(UDisksBlock * block,GDBusMethodInvocation * invocation,GUnixFDList * fd_list,GVariant * options)3582 handle_open_for_backup (UDisksBlock *block,
3583 GDBusMethodInvocation *invocation,
3584 GUnixFDList *fd_list,
3585 GVariant *options)
3586 {
3587 UDisksObject *object;
3588 UDisksDaemon *daemon;
3589 UDisksState *state = NULL;
3590 const gchar *action_id;
3591 const gchar *device;
3592 GUnixFDList *out_fd_list = NULL;
3593 GError *error = NULL;
3594 gint fd = -1;
3595
3596 object = udisks_daemon_util_dup_object (block, &error);
3597 if (object == NULL)
3598 {
3599 g_dbus_method_invocation_take_error (invocation, error);
3600 goto out;
3601 }
3602
3603 daemon = udisks_linux_block_object_get_daemon (UDISKS_LINUX_BLOCK_OBJECT (object));
3604 state = udisks_daemon_get_state (daemon);
3605
3606 udisks_linux_block_object_lock_for_cleanup (UDISKS_LINUX_BLOCK_OBJECT (object));
3607 udisks_state_check_block (state, udisks_linux_block_object_get_device_number (UDISKS_LINUX_BLOCK_OBJECT (object)));
3608
3609 action_id = "org.freedesktop.udisks2.open-device";
3610 if (udisks_block_get_hint_system (block))
3611 action_id = "org.freedesktop.udisks2.open-device-system";
3612
3613 if (!udisks_daemon_util_check_authorization_sync (daemon,
3614 object,
3615 action_id,
3616 options,
3617 /* Translators: Shown in authentication dialog when creating a
3618 * disk image file.
3619 *
3620 * Do not translate $(drive), it's a placeholder and will
3621 * be replaced by the name of the drive/device in question
3622 */
3623 N_("Authentication is required to open $(drive) for reading"),
3624 invocation))
3625 goto out;
3626
3627 device = udisks_block_get_device (UDISKS_BLOCK (block));
3628
3629 fd = open_device (device, "r", O_CLOEXEC | O_EXCL, &error);
3630 if (fd == -1)
3631 {
3632 g_dbus_method_invocation_take_error (invocation, error);
3633 goto out;
3634 }
3635
3636 out_fd_list = g_unix_fd_list_new_from_array (&fd, 1);
3637 udisks_block_complete_open_for_backup (block, invocation, out_fd_list, g_variant_new_handle (0));
3638
3639 out:
3640 if (object != NULL)
3641 udisks_linux_block_object_release_cleanup_lock (UDISKS_LINUX_BLOCK_OBJECT (object));
3642 if (state != NULL)
3643 udisks_state_check (state);
3644 g_clear_object (&out_fd_list);
3645 g_clear_object (&object);
3646 return TRUE; /* returning true means that we handled the method invocation */
3647 }
3648
3649 /* ---------------------------------------------------------------------------------------------------- */
3650
3651 static gboolean
handle_open_for_restore(UDisksBlock * block,GDBusMethodInvocation * invocation,GUnixFDList * fd_list,GVariant * options)3652 handle_open_for_restore (UDisksBlock *block,
3653 GDBusMethodInvocation *invocation,
3654 GUnixFDList *fd_list,
3655 GVariant *options)
3656 {
3657 UDisksObject *object;
3658 UDisksDaemon *daemon;
3659 UDisksState *state = NULL;
3660 const gchar *action_id;
3661 const gchar *device;
3662 GUnixFDList *out_fd_list = NULL;
3663 GError *error;
3664 gint fd;
3665
3666 error = NULL;
3667 object = udisks_daemon_util_dup_object (block, &error);
3668 if (object == NULL)
3669 {
3670 g_dbus_method_invocation_take_error (invocation, error);
3671 goto out;
3672 }
3673
3674 daemon = udisks_linux_block_object_get_daemon (UDISKS_LINUX_BLOCK_OBJECT (object));
3675 state = udisks_daemon_get_state (daemon);
3676
3677 udisks_linux_block_object_lock_for_cleanup (UDISKS_LINUX_BLOCK_OBJECT (object));
3678 udisks_state_check_block (state, udisks_linux_block_object_get_device_number (UDISKS_LINUX_BLOCK_OBJECT (object)));
3679
3680 action_id = "org.freedesktop.udisks2.open-device";
3681 if (udisks_block_get_hint_system (block))
3682 action_id = "org.freedesktop.udisks2.open-device-system";
3683
3684 if (!udisks_daemon_util_check_authorization_sync (daemon,
3685 object,
3686 action_id,
3687 options,
3688 /* Translators: Shown in authentication dialog when restoring
3689 * from a disk image file.
3690 *
3691 * Do not translate $(drive), it's a placeholder and will
3692 * be replaced by the name of the drive/device in question
3693 */
3694 N_("Authentication is required to open $(drive) for writing"),
3695 invocation))
3696 goto out;
3697
3698
3699 device = udisks_block_get_device (UDISKS_BLOCK (block));
3700
3701 fd = open_device (device, "w", O_SYNC | O_CLOEXEC | O_EXCL, &error);
3702 if (fd == -1)
3703 {
3704 g_dbus_method_invocation_take_error (invocation, error);
3705 goto out;
3706 }
3707
3708 out_fd_list = g_unix_fd_list_new_from_array (&fd, 1);
3709 udisks_block_complete_open_for_restore (block, invocation, out_fd_list, g_variant_new_handle (0));
3710
3711 out:
3712 if (object != NULL)
3713 udisks_linux_block_object_release_cleanup_lock (UDISKS_LINUX_BLOCK_OBJECT (object));
3714 if (state != NULL)
3715 udisks_state_check (state);
3716 g_clear_object (&out_fd_list);
3717 g_clear_object (&object);
3718 return TRUE; /* returning true means that we handled the method invocation */
3719 }
3720
3721 /* ---------------------------------------------------------------------------------------------------- */
3722
3723 static gboolean
handle_open_for_benchmark(UDisksBlock * block,GDBusMethodInvocation * invocation,GUnixFDList * fd_list,GVariant * options)3724 handle_open_for_benchmark (UDisksBlock *block,
3725 GDBusMethodInvocation *invocation,
3726 GUnixFDList *fd_list,
3727 GVariant *options)
3728 {
3729 UDisksObject *object;
3730 UDisksDaemon *daemon;
3731 UDisksState *state = NULL;
3732 const gchar *action_id;
3733 const gchar *device;
3734 GUnixFDList *out_fd_list = NULL;
3735 gboolean opt_writable = FALSE;
3736 GError *error = NULL;
3737 gint fd = -1;
3738 const gchar *open_mode = NULL;
3739 gint open_flags;
3740
3741 object = udisks_daemon_util_dup_object (block, &error);
3742 if (object == NULL)
3743 {
3744 g_dbus_method_invocation_take_error (invocation, error);
3745 goto out;
3746 }
3747
3748 daemon = udisks_linux_block_object_get_daemon (UDISKS_LINUX_BLOCK_OBJECT (object));
3749 state = udisks_daemon_get_state (daemon);
3750
3751 udisks_linux_block_object_lock_for_cleanup (UDISKS_LINUX_BLOCK_OBJECT (object));
3752 udisks_state_check_block (state, udisks_linux_block_object_get_device_number (UDISKS_LINUX_BLOCK_OBJECT (object)));
3753
3754 action_id = "org.freedesktop.udisks2.open-device";
3755 if (udisks_block_get_hint_system (block))
3756 action_id = "org.freedesktop.udisks2.open-device-system";
3757
3758 if (!udisks_daemon_util_check_authorization_sync (daemon,
3759 object,
3760 action_id,
3761 options,
3762 /* Translators: Shown in authentication dialog when an application
3763 * wants to benchmark a device.
3764 *
3765 * Do not translate $(drive), it's a placeholder and will
3766 * be replaced by the name of the drive/device in question
3767 */
3768 N_("Authentication is required to open $(drive) for benchmarking"),
3769 invocation))
3770 goto out;
3771
3772 g_variant_lookup (options, "writable", "b", &opt_writable);
3773
3774 open_flags = O_DIRECT | O_SYNC | O_CLOEXEC;
3775 if (opt_writable)
3776 {
3777 open_flags |= O_EXCL;
3778 open_mode = "rw";
3779 }
3780 else
3781 open_mode = "r";
3782
3783 device = udisks_block_get_device (UDISKS_BLOCK (block));
3784
3785 fd = open_device (device, open_mode, open_flags, &error);
3786 if (fd == -1)
3787 {
3788 g_dbus_method_invocation_take_error (invocation, error);
3789 goto out;
3790 }
3791
3792 out_fd_list = g_unix_fd_list_new_from_array (&fd, 1);
3793 udisks_block_complete_open_for_benchmark (block, invocation, out_fd_list, g_variant_new_handle (0));
3794
3795 out:
3796 if (object != NULL)
3797 udisks_linux_block_object_release_cleanup_lock (UDISKS_LINUX_BLOCK_OBJECT (object));
3798 if (state != NULL)
3799 udisks_state_check (state);
3800 g_clear_object (&out_fd_list);
3801 g_clear_object (&object);
3802 return TRUE; /* returning true means that we handled the method invocation */
3803 }
3804
3805 /* ---------------------------------------------------------------------------------------------------- */
3806
3807 static gboolean
handle_open_device(UDisksBlock * block,GDBusMethodInvocation * invocation,GUnixFDList * fd_list,const gchar * mode,GVariant * options)3808 handle_open_device (UDisksBlock *block,
3809 GDBusMethodInvocation *invocation,
3810 GUnixFDList *fd_list,
3811 const gchar *mode,
3812 GVariant *options)
3813 {
3814 UDisksObject *object;
3815 UDisksDaemon *daemon;
3816 UDisksState *state = NULL;
3817 const gchar *action_id;
3818 const gchar *device;
3819 GUnixFDList *out_fd_list = NULL;
3820 GError *error = NULL;
3821 gint fd = -1;
3822 gint flags = 0;
3823
3824 object = udisks_daemon_util_dup_object (block, &error);
3825 if (object == NULL)
3826 {
3827 g_dbus_method_invocation_take_error (invocation, error);
3828 goto out;
3829 }
3830
3831 daemon = udisks_linux_block_object_get_daemon (UDISKS_LINUX_BLOCK_OBJECT (object));
3832 state = udisks_daemon_get_state (daemon);
3833
3834 udisks_linux_block_object_lock_for_cleanup (UDISKS_LINUX_BLOCK_OBJECT (object));
3835 udisks_state_check_block (state, udisks_linux_block_object_get_device_number (UDISKS_LINUX_BLOCK_OBJECT (object)));
3836
3837 action_id = "org.freedesktop.udisks2.open-device";
3838 if (udisks_block_get_hint_system (block))
3839 action_id = "org.freedesktop.udisks2.open-device-system";
3840
3841 if (!udisks_daemon_util_check_authorization_sync (daemon,
3842 object,
3843 action_id,
3844 options,
3845 /* Translators: Shown in authentication dialog when an application
3846 * wants to benchmark a device.
3847 *
3848 * Do not translate $(drive), it's a placeholder and will
3849 * be replaced by the name of the drive/device in question
3850 */
3851 N_("Authentication is required to open $(drive)."),
3852 invocation))
3853 goto out;
3854
3855 device = udisks_block_get_device (UDISKS_BLOCK (block));
3856
3857 g_variant_lookup (options, "flags", "i", &flags);
3858
3859 fd = open_device (device, mode, flags, &error);
3860 if (fd == -1)
3861 {
3862 g_dbus_method_invocation_take_error (invocation, error);
3863 goto out;
3864 }
3865
3866 out_fd_list = g_unix_fd_list_new_from_array (&fd, 1);
3867 udisks_block_complete_open_device (block, invocation, out_fd_list, g_variant_new_handle (0));
3868
3869 out:
3870 if (object != NULL)
3871 udisks_linux_block_object_release_cleanup_lock (UDISKS_LINUX_BLOCK_OBJECT (object));
3872 if (state != NULL)
3873 udisks_state_check (state);
3874 g_clear_object (&out_fd_list);
3875 g_clear_object (&object);
3876 return TRUE; /* returning true means that we handled the method invocation */
3877 }
3878
3879 /* ---------------------------------------------------------------------------------------------------- */
3880
3881 static gboolean
handle_rescan(UDisksBlock * block,GDBusMethodInvocation * invocation,GVariant * options)3882 handle_rescan (UDisksBlock *block,
3883 GDBusMethodInvocation *invocation,
3884 GVariant *options)
3885 {
3886 UDisksObject *object = NULL;
3887 UDisksLinuxDevice *device = NULL;
3888 UDisksDaemon *daemon;
3889 const gchar *action_id;
3890 const gchar *message;
3891 GError *error = NULL;
3892
3893 object = udisks_daemon_util_dup_object (block, &error);
3894 if (object == NULL)
3895 {
3896 g_dbus_method_invocation_take_error (invocation, error);
3897 goto out;
3898 }
3899
3900 daemon = udisks_linux_block_object_get_daemon (UDISKS_LINUX_BLOCK_OBJECT (object));
3901
3902 /* Translators: Shown in authentication dialog when an application
3903 * wants to rescan a device.
3904 *
3905 * Do not translate $(drive), it's a placeholder and will
3906 * be replaced by the name of the drive/device in question
3907 */
3908 message = N_("Authentication is required to rescan $(drive)");
3909 action_id = "org.freedesktop.udisks2.rescan";
3910
3911 if (!udisks_daemon_util_check_authorization_sync (daemon,
3912 object,
3913 action_id,
3914 options,
3915 message,
3916 invocation))
3917 goto out;
3918
3919 device = udisks_linux_block_object_get_device (UDISKS_LINUX_BLOCK_OBJECT (object));
3920
3921 udisks_linux_block_object_trigger_uevent_sync (UDISKS_LINUX_BLOCK_OBJECT (object),
3922 UDISKS_DEFAULT_WAIT_TIMEOUT);
3923 if (g_strcmp0 (g_udev_device_get_devtype (device->udev_device), "disk") == 0)
3924 udisks_linux_block_object_reread_partition_table (UDISKS_LINUX_BLOCK_OBJECT (object));
3925
3926 udisks_block_complete_rescan (block, invocation);
3927
3928 out:
3929 g_clear_object (&device);
3930 g_clear_object (&object);
3931 return TRUE; /* returning true means that we handled the method invocation */
3932 }
3933
3934 /* ---------------------------------------------------------------------------------------------------- */
3935
3936 static void
block_iface_init(UDisksBlockIface * iface)3937 block_iface_init (UDisksBlockIface *iface)
3938 {
3939 iface->handle_get_secret_configuration = handle_get_secret_configuration;
3940 iface->handle_add_configuration_item = handle_add_configuration_item;
3941 iface->handle_remove_configuration_item = handle_remove_configuration_item;
3942 iface->handle_update_configuration_item = handle_update_configuration_item;
3943 iface->handle_format = handle_format;
3944 iface->handle_open_for_backup = handle_open_for_backup;
3945 iface->handle_open_for_restore = handle_open_for_restore;
3946 iface->handle_open_for_benchmark = handle_open_for_benchmark;
3947 iface->handle_open_device = handle_open_device;
3948 iface->handle_rescan = handle_rescan;
3949 }
3950