xref: /titanic_44/usr/src/cmd/hal/tools/hal-storage-shared.c (revision 672986541be54a7a471bb088e60780c37e371d7e)
1 /***************************************************************************
2  * CVSID: $Id: hal-storage-mount.c,v 1.7 2006/06/21 00:44:03 david Exp $
3  *
4  * hal-storage-mount.c : Mount wrapper
5  *
6  * Copyright (C) 2006 David Zeuthen, <david@fubar.dk>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21  *
22  **************************************************************************/
23 
24 
25 #ifdef HAVE_CONFIG_H
26 #  include <config.h>
27 #endif
28 
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <glib.h>
33 #include <glib/gstdio.h>
34 #ifdef __FreeBSD__
35 #include <fstab.h>
36 #include <sys/param.h>
37 #include <sys/ucred.h>
38 #include <sys/mount.h>
39 #include <limits.h>
40 #include <pwd.h>
41 #elif sun
42 #include <fcntl.h>
43 #include <sys/mnttab.h>
44 #include <sys/vfstab.h>
45 #include <sys/stat.h>
46 #include <sys/wait.h>
47 #include <bsm/adt.h>
48 #include <bsm/adt_event.h>
49 #else
50 #include <mntent.h>
51 #endif
52 #include <sys/types.h>
53 #include <unistd.h>
54 #include <sys/file.h>
55 #include <errno.h>
56 #include <syslog.h>
57 
58 #include "hal-storage-shared.h"
59 
60 #ifdef __FreeBSD__
61 struct mtab_handle
62 {
63   struct statfs	*mounts;
64   int		n_mounts;
65   int		iter;
66 };
67 #endif
68 
69 
70 gboolean
71 mtab_open (gpointer *handle)
72 {
73 #ifdef __FreeBSD__
74 	struct mtab_handle *mtab;
75 
76 	mtab = g_new0 (struct mtab_handle, 1);
77 	mtab->n_mounts = getmntinfo (&mtab->mounts, MNT_NOWAIT);
78 	if (mtab->n_mounts == 0) {
79 		g_free (mtab);
80 		return FALSE;
81 	}
82 
83 	*handle = mtab;
84 	return TRUE;
85 #elif sun
86 	*handle = fopen (MNTTAB, "r");
87 	return *handle != NULL;
88 #else
89 	*handle = fopen ("/proc/mounts", "r");
90 	return *handle != NULL;
91 #endif
92 }
93 
94 char *
95 mtab_next (gpointer handle, char **mount_point)
96 {
97 #ifdef __FreeBSD__
98 	struct mtab_handle *mtab = handle;
99 
100 	if (mtab->iter < mtab->n_mounts)
101 		return mtab->mounts[mtab->iter++].f_mntfromname;
102 	else
103 		return NULL;
104 #error TODO: set *mount_point to g_strdup()-ed value if mount_point!=NULL
105 #elif sun
106 	static struct mnttab mnt;
107 
108 	if (getmntent (handle, &mnt) == 0) {
109 		if (mount_point != NULL) {
110 			*mount_point = g_strdup (mnt.mnt_mountp);
111 		}
112 		return mnt.mnt_special;
113 	} else {
114 		return NULL;
115 	}
116 #else
117 	struct mntent *mnt;
118 
119 	mnt = getmntent (handle);
120 
121 	if (mnt != NULL) {
122 		if (mount_point != NULL) {
123 			*mount_point = g_strdup (mnt->mnt_dir);
124 		}
125 		return mnt->mnt_fsname;
126 	} else {
127 		return NULL;
128 	}
129 #endif
130 }
131 
132 void
133 mtab_close (gpointer handle)
134 {
135 #ifdef __FreeBSD__
136 	g_free (handle);
137 #else
138 	fclose (handle);
139 #endif
140 }
141 
142 
143 
144 gboolean
145 fstab_open (gpointer *handle)
146 {
147 #ifdef __FreeBSD__
148 	return setfsent () == 1;
149 #elif sun
150 	*handle = fopen (VFSTAB, "r");
151 	return *handle != NULL;
152 #else
153 	*handle = fopen ("/etc/fstab", "r");
154 	return *handle != NULL;
155 #endif
156 }
157 
158 char *
159 fstab_next (gpointer handle, char **mount_point)
160 {
161 #ifdef __FreeBSD__
162 	struct fstab *fstab;
163 
164 	fstab = getfsent ();
165 
166 	/* TODO: fill out mount_point */
167 	if (mount_point != NULL && fstab != NULL) {
168 		*mount_point = fstab->fs_file;
169 	}
170 
171 	return fstab ? fstab->fs_spec : NULL;
172 #elif sun
173 	static struct vfstab v;
174 
175 	return getvfsent (handle, &v) == 0 ? v.vfs_special : NULL;
176 #else
177 	struct mntent *mnt;
178 
179 	mnt = getmntent (handle);
180 
181 	if (mount_point != NULL && mnt != NULL) {
182 		*mount_point = mnt->mnt_dir;
183 	}
184 
185 	return mnt ? mnt->mnt_fsname : NULL;
186 #endif
187 }
188 
189 void
190 fstab_close (gpointer handle)
191 {
192 #ifdef __FreeBSD__
193 	endfsent ();
194 #else
195 	fclose (handle);
196 #endif
197 }
198 
199 #ifdef __FreeBSD__
200 #define UMOUNT		"/sbin/umount"
201 #elif sun
202 #define UMOUNT		"/sbin/umount"
203 #else
204 #define UMOUNT		"/bin/umount"
205 #endif
206 
207 void
208 unknown_error (const char *detail)
209 {
210 	fprintf (stderr, "org.freedesktop.Hal.Device.Volume.UnknownFailure\n");
211 	fprintf (stderr, "%s\n", detail);
212 	exit (1);
213 }
214 
215 
216 static void
217 device_busy (const char *detail)
218 {
219 	fprintf (stderr, "org.freedesktop.Hal.Device.Volume.Busy\n");
220 	fprintf (stderr, "%s\n", detail);
221 	exit (1);
222 }
223 
224 
225 static void
226 not_mounted (const char *detail)
227 {
228 	fprintf (stderr, "org.freedesktop.Hal.Device.Volume.NotMounted\n");
229 	fprintf (stderr, "%s\n", detail);
230 	exit (1);
231 }
232 
233 
234 static void
235 not_mounted_by_hal (const char *detail)
236 {
237 	fprintf (stderr, "org.freedesktop.Hal.Device.Volume.NotMountedByHal\n");
238 	fprintf (stderr, "%s\n", detail);
239 	exit (1);
240 }
241 
242 static void
243 permission_denied_privilege (const char *privilege, const char *uid)
244 {
245 	fprintf (stderr, "org.freedesktop.Hal.Device.PermissionDeniedByPolicy\n");
246 	fprintf (stderr, "%s refused uid %s\n", privilege, uid);
247 	exit (1);
248 }
249 
250 static void
251 permission_denied_volume_ignore (const char *device)
252 {
253 	fprintf (stderr, "org.freedesktop.Hal.Device.Volume.PermissionDenied\n");
254 	fprintf (stderr, "Device has %s volume.ignore set to TRUE. Refusing to mount.\n", device);
255 	exit (1);
256 }
257 
258 void
259 handle_unmount (LibHalContext *hal_ctx,
260 #ifdef HAVE_POLKIT
261 		LibPolKitContext *pol_ctx,
262 #endif
263 		const char *udi,
264 		LibHalVolume *volume, LibHalDrive *drive, const char *device,
265 		const char *invoked_by_uid, const char *invoked_by_syscon_name,
266 		gboolean option_lazy, gboolean option_force,
267 		DBusConnection *system_bus)
268 {
269 	int i, j;
270 	DBusError error;
271 	GError *err = NULL;
272 	char *sout = NULL;
273 	char *serr = NULL;
274 	int exit_status;
275 	char *args[10];
276 	int na;
277 	FILE *hal_mtab_orig;
278 	int hal_mtab_orig_len;
279 	int num_read;
280 	char *hal_mtab_buf;
281 	char **lines;
282 	char *mount_point_to_unmount;
283 	gboolean mounted_by_other_uid;
284 	FILE *hal_mtab_new;
285 #ifdef sun
286 	adt_export_data_t *adt_data;
287 	size_t adt_data_size;
288 #endif
289 
290 #ifdef DEBUG
291 	printf ("device                           = %s\n", device);
292 	printf ("invoked by uid                   = %s\n", invoked_by_uid);
293 	printf ("invoked by system bus connection = %s\n", invoked_by_syscon_name);
294 #endif
295 
296 	if (volume != NULL) {
297 		dbus_error_init (&error);
298 		if (libhal_device_get_property_bool (hal_ctx, udi, "volume.ignore", &error) ||
299 		    dbus_error_is_set (&error)) {
300 			if (dbus_error_is_set (&error)) {
301 				LIBHAL_FREE_DBUS_ERROR (&error);
302 			}
303 			/*
304 			 * When device allocation is enabled (bsmconv or TX), we
305 			 * set volume.ignore on all volumes, but still want
306 			 * Mount() to succeed when called from the euid=0
307 			 * device allocation program.
308 			 */
309 			if (atol (invoked_by_uid) != 0) {
310 				permission_denied_volume_ignore (device);
311 			}
312 		}
313 
314 		if (!libhal_volume_is_mounted (volume)) {
315 			not_mounted ("According to HAL, the volume is not mounted");
316 		}
317 	}
318 
319 
320 	/* check hal's mtab file to verify the device to unmount is actually mounted by hal */
321 	hal_mtab_orig = fopen ("/media/.hal-mtab", "r");
322 	if (hal_mtab_orig == NULL) {
323 		unknown_error ("Cannot open /media/.hal-mtab");
324 	}
325 	if (fseek (hal_mtab_orig, 0L, SEEK_END) != 0) {
326 		unknown_error ("Cannot seek to end of /media/.hal-mtab");
327 	}
328 	hal_mtab_orig_len = ftell (hal_mtab_orig);
329 	if (hal_mtab_orig_len < 0) {
330 		unknown_error ("Cannot determine size of /media/.hal-mtab");
331 	}
332 	rewind (hal_mtab_orig);
333 	hal_mtab_buf = g_new0 (char, hal_mtab_orig_len + 1);
334 	num_read = fread (hal_mtab_buf, 1, hal_mtab_orig_len, hal_mtab_orig);
335 	if (num_read != hal_mtab_orig_len) {
336 		unknown_error ("Cannot read from /media/.hal-mtab");
337 	}
338 	fclose (hal_mtab_orig);
339 
340 #ifdef DEBUG
341 	printf ("hal_mtab = '%s'\n", hal_mtab_buf);
342 #endif
343 
344 	lines = g_strsplit (hal_mtab_buf, "\n", 0);
345 	g_free (hal_mtab_buf);
346 
347 	mount_point_to_unmount = NULL;
348 	mounted_by_other_uid = TRUE;
349 
350 	/* find the entry we're going to unmount */
351 	for (i = 0; lines[i] != NULL; i++) {
352 		char **line_elements;
353 		char *special, *dosp;
354 		struct stat st;
355 
356 #ifdef DEBUG
357 		printf (" line = '%s'\n", lines[i]);
358 #endif
359 
360 		if ((lines[i])[0] == '#')
361 			continue;
362 
363 		line_elements = g_strsplit (lines[i], "\t", 6);
364 		if (g_strv_length (line_elements) == 6) {
365 
366 #ifdef DEBUG
367 			printf ("  devfile     = '%s'\n", line_elements[0]);
368 			printf ("  uid         = '%s'\n", line_elements[1]);
369 			printf ("  session id  = '%s'\n", line_elements[2]);
370 			printf ("  fs          = '%s'\n", line_elements[3]);
371 			printf ("  options     = '%s'\n", line_elements[4]);
372 			printf ("  mount_point = '%s'\n", line_elements[5]);
373 #endif
374 
375 			if (strcmp (line_elements[0], device) == 0) {
376 				char *line_to_free;
377 
378 				if (strcmp (line_elements[1], invoked_by_uid) == 0) {
379 					mounted_by_other_uid = FALSE;
380 				}
381 #ifdef sun
382 				if (stat("/dev/console", &st) == 0 &&
383 				    st.st_uid == atoi (invoked_by_uid)) {
384 					/*
385 					 * Owner is allowed to take over. Before we have real
386 					 * ownership in HAL, assume it's the console owner.
387 					 */
388 					mounted_by_other_uid = FALSE;
389 				}
390 #endif /* sun */
391 				mount_point_to_unmount = g_strdup (line_elements[5]);
392 
393 				line_to_free = lines[i];
394 
395 				for (j = i; lines[j] != NULL; j++) {
396 					lines[j] = lines[j+1];
397 				}
398 				lines[j] = NULL;
399 
400 				g_free (line_to_free);
401 
402 				g_strfreev (line_elements);
403 				goto line_found;
404 
405 			}
406 
407 		}
408 
409 		g_strfreev (line_elements);
410 	}
411 line_found:
412 
413 	if (mount_point_to_unmount == NULL) {
414 		not_mounted_by_hal ("Device to unmount is not in /media/.hal-mtab so it is not mounted by HAL");
415 	}
416 
417 	/* bail out, unless if we got the "hal-storage-can-unmount-volumes-mounted-by-others" privilege only
418 	 * if mounted_by_other_uid==TRUE
419 	 *
420 	 * We allow uid 0 to actually ensure that Unmount(options=["lazy"], "/dev/blah") works from addon-storage.
421 	 */
422 	if ((strcmp (invoked_by_uid, "0") != 0) && mounted_by_other_uid) {
423 		/* TODO: actually check for privilege "hal-storage-can-unmount-volumes-mounted-by-others" */
424 		permission_denied_privilege ("hal-storage-can-unmount-volumes-mounted-by-others", invoked_by_uid);
425 	}
426 
427 	/* create new .hal-mtab~ file without the entry we're going to unmount */
428 	hal_mtab_new = fopen ("/media/.hal-mtab~", "w");
429 	if (hal_mtab_new == NULL) {
430 		unknown_error ("Cannot create /media/.hal-mtab~");
431 	}
432 	for (i = 0; lines[i] != NULL; i++) {
433 		if (i > 0) {
434 			char anewl[2] = "\n\0";
435 			if (fwrite (anewl, 1, 1, hal_mtab_new) != 1) {
436 				unknown_error ("Cannot write to /media/.hal-mtab~");
437 			}
438 		}
439 
440 		if (fwrite (lines[i], 1, strlen (lines[i]), hal_mtab_new) != strlen (lines[i])) {
441 			unknown_error ("Cannot write to /media/.hal-mtab~");
442 		}
443 
444 	}
445 	fclose (hal_mtab_new);
446 
447 	g_strfreev (lines);
448 
449 	/* construct arguments to /bin/umount */
450 	na = 0;
451 	args[na++] = UMOUNT;
452 	if (option_lazy)
453 		args[na++] = "-l";
454 	if (option_force)
455 		args[na++] = "-f";
456 	args[na++] = (char *) device;
457 	args[na++] = NULL;
458 
459 #ifdef DEBUG
460 	printf ("will umount %s (mounted at '%s'), mounted_by_other_uid=%d\n",
461 		device, mount_point_to_unmount, mounted_by_other_uid);
462 #endif
463 
464 	/* invoke /bin/umount */
465 	if (!g_spawn_sync ("/",
466 			   args,
467 			   NULL,
468 			   0,
469 			   NULL,
470 			   NULL,
471 			   &sout,
472 			   &serr,
473 			   &exit_status,
474 			   &err)) {
475 		printf ("Cannot execute %s\n", UMOUNT);
476 		unlink ("/media/.hal-mtab~");
477 		unknown_error ("Cannot spawn " UMOUNT);
478 	}
479 
480 	/* check if unmount was succesful */
481 	if (exit_status != 0) {
482 		printf ("%s error %d, stdout='%s', stderr='%s'\n", UMOUNT, exit_status, sout, serr);
483 
484 		if (strstr (serr, "device is busy") != NULL) {
485 			unlink ("/media/.hal-mtab~");
486 			device_busy (serr);
487 		} else {
488 			unlink ("/media/.hal-mtab~");
489 			unknown_error (serr);
490 		}
491 	}
492 
493 #ifdef sun
494 	if ((adt_data = get_audit_export_data (system_bus,
495 	    invoked_by_syscon_name, &adt_data_size)) != NULL) {
496 		audit_volume (adt_data, ADT_detach, WEXITSTATUS(exit_status),
497 		    "solaris.device.mount.removable",
498 		    mount_point_to_unmount, device, NULL);
499 		free (adt_data);
500 	}
501 #endif
502 
503 	/* unmount was succesful, remove directory we created in Mount() */
504 #ifdef sun
505 	if (strncmp (mount_point_to_unmount, "/media/", 7) == 0)
506 #endif
507 	if (g_rmdir (mount_point_to_unmount) != 0) {
508 		unlink ("/media/.hal-mtab~");
509 		unknown_error ("Cannot remove directory");
510 	}
511 
512 	/* set new .hal-mtab file */
513 	if (rename ("/media/.hal-mtab~", "/media/.hal-mtab") != 0) {
514 		unlink ("/media/.hal-mtab~");
515 		unknown_error ("Cannot rename /media/.hal-mtab~ to /media/.hal-mtab");
516 	}
517 
518 #ifdef DEBUG
519 	printf ("done unmounting\n");
520 #endif
521 	openlog ("hald", 0, LOG_DAEMON);
522 	syslog (LOG_INFO, "unmounted %s from '%s' on behalf of uid %s", device, mount_point_to_unmount, invoked_by_uid);
523 	closelog ();
524 
525 	g_free (sout);
526 	g_free (serr);
527 	g_free (mount_point_to_unmount);
528 }
529 
530 #define EJECT "/usr/bin/eject"
531 
532 void
533 handle_eject (LibHalContext *hal_ctx,
534 #ifdef HAVE_POLKIT
535 	      LibPolKitContext *pol_ctx,
536 #endif
537 	      const char *udi,
538 	      LibHalDrive *drive, const char *device,
539 	      const char *invoked_by_uid, const char *invoked_by_syscon_name,
540 	      gboolean closetray, DBusConnection *system_bus)
541 {
542 	GError *err = NULL;
543 	char *sout = NULL;
544 	char *serr = NULL;
545 	int exit_status;
546 	char *args[10];
547 	int na;
548 #ifdef sun
549 	adt_export_data_t *adt_data;
550 	size_t adt_data_size;
551 #endif
552 	/* TODO: should we require privileges here? */
553 
554 #ifdef DEBUG
555 	printf ("device                           = %s\n", device);
556 	printf ("invoked by uid                   = %s\n", invoked_by_uid);
557 	printf ("invoked by system bus connection = %s\n", invoked_by_syscon_name);
558 #endif
559 
560 	/* construct arguments to EJECT (e.g. /usr/bin/eject) */
561 	na = 0;
562 	args[na++] = EJECT;
563 	if (closetray) {
564 		args[na++] = "-t";
565 	}
566 	args[na++] = (char *) device;
567 	args[na++] = NULL;
568 
569 #ifdef sun
570 	putenv("EJECT_DIRECT=1");
571 #endif
572 
573 #ifdef DEBUG
574 	printf ("will eject %s\n", device);
575 #endif
576 
577 	/* invoke eject command */
578 	if (!g_spawn_sync ("/",
579 			   args,
580 			   NULL,
581 			   0,
582 			   NULL,
583 			   NULL,
584 			   &sout,
585 			   &serr,
586 			   &exit_status,
587 			   &err)) {
588 		printf ("Cannot execute %s\n", EJECT);
589 		unknown_error ("Cannot spawn " EJECT);
590 	}
591 
592 #ifdef sun
593 	/*
594 	 * Solaris eject returns 4 for manually ejectable media like floppy.
595 	 * Consider it success.
596 	 */
597 	if (WEXITSTATUS(exit_status) == 4) {
598 		exit_status = 0;
599 	}
600 
601 	if ((adt_data = get_audit_export_data (system_bus,
602 	    invoked_by_syscon_name, &adt_data_size)) != NULL) {
603 		audit_volume (adt_data, ADT_remove, WEXITSTATUS(exit_status),
604 		    "solaris.device.mount.removable", NULL, device, NULL);
605 		free (adt_data);
606 	}
607 #endif /* sun */
608 
609 	/* check if eject was succesful */
610 	if (exit_status != 0) {
611 		printf ("%s error %d, stdout='%s', stderr='%s'\n", EJECT, exit_status, sout, serr);
612 
613 		unknown_error (serr);
614 	}
615 
616 	/* eject was succesful... */
617 
618 #ifdef DEBUG
619 	printf ("done ejecting\n");
620 #endif
621 
622 	g_free (sout);
623 	g_free (serr);
624 }
625 
626 
627 static int lock_mtab_fd = -1;
628 
629 gboolean
630 lock_hal_mtab (void)
631 {
632 	if (lock_mtab_fd >= 0)
633 		return TRUE;
634 
635 	printf ("%d: XYA attempting to get lock on /media/.hal-mtab-lock\n", getpid ());
636 
637 	lock_mtab_fd = open ("/media/.hal-mtab-lock", O_CREAT | O_RDWR);
638 
639 	if (lock_mtab_fd < 0)
640 		return FALSE;
641 
642 tryagain:
643 #if sun
644 	if (lockf (lock_mtab_fd, F_LOCK, 0) != 0) {
645 #else
646 	if (flock (lock_mtab_fd, LOCK_EX) != 0) {
647 #endif
648 		if (errno == EINTR)
649 			goto tryagain;
650 		return FALSE;
651 	}
652 
653 	printf ("%d: XYA got lock on /media/.hal-mtab-lock\n", getpid ());
654 
655 
656 	return TRUE;
657 }
658 
659 void
660 unlock_hal_mtab (void)
661 {
662 #if sun
663 	lockf (lock_mtab_fd, F_ULOCK, 0);
664 #else
665 	flock (lock_mtab_fd, LOCK_UN);
666 #endif
667 	close (lock_mtab_fd);
668 	lock_mtab_fd = -1;
669 	printf ("%d: XYA released lock on /media/.hal-mtab-lock\n", getpid ());
670 }
671 
672 #if sun
673 
674 /* map PolicyKit privilege to RBAC authorization */
675 char *
676 auth_from_privilege(const char *privilege)
677 {
678 	char *authname;
679 	int i;
680 
681 	if (strcmp (privilege, "hal-storage-removable-mount") == 0) {
682 		authname = g_strdup ("solaris.device.mount.removable");
683 	} else if (strcmp (privilege, "hal-storage-removable-mount-all-options") == 0) {
684 		authname = g_strdup ("solaris.device.mount.alloptions.removable");
685 	} else if (strcmp (privilege, "hal-storage-fixed-mount") == 0) {
686 		authname = g_strdup ("solaris.device.mount.fixed");
687 	} else if (strcmp (privilege, "hal-storage-fixed-mount-all-options") == 0) {
688 		authname = g_strdup ("solaris.device.mount.alloptions.fixed");
689 	} else {
690 		/* replace '-' with '.' */
691 		authname = g_strdup (privilege);
692 		for (i = 0; i < strlen (authname); i++) {
693 			if (authname[i] == '-') {
694 				authname[i] = '.';
695 			}
696 		}
697 	}
698 	return (authname);
699 }
700 
701 adt_export_data_t *
702 get_audit_export_data(DBusConnection *bus, const char *invoked_by_syscon_name, size_t *data_size)
703 {
704 	DBusMessage *message;
705 	DBusMessage *reply;
706 	DBusMessageIter iter, subiter;
707 	DBusError error;
708 	int count, bufsize;
709 	uchar_t *buf;
710 	uchar_t value;
711 
712 	message = dbus_message_new_method_call ("org.freedesktop.DBus",
713 						"/org/freedesktop/DBus",
714 						"org.freedesktop.DBus",
715 						"GetAuditSessionData");
716 	if (message == NULL) {
717 		printf ("cannot get message\n");
718 		return NULL;
719 	}
720 
721 	if (!dbus_message_append_args(message, DBUS_TYPE_STRING, &invoked_by_syscon_name,
722 	    DBUS_TYPE_INVALID)) {
723 		dbus_message_unref(message);
724 		return NULL;
725 	}
726 
727 	dbus_error_init (&error);
728 	reply = dbus_connection_send_with_reply_and_block (bus,
729 							   message, -1,
730 							   &error);
731 	if (dbus_error_is_set (&error)) {
732 		printf ("send failed %s\n", error.message);
733 		dbus_error_free (&error);
734 		dbus_message_unref (message);
735 		return NULL;
736 	}
737 	if (reply == NULL) {
738 		dbus_message_unref (message);
739 		return NULL;
740 	}
741 
742 	dbus_message_iter_init (reply, &iter);
743 
744 	if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_ARRAY  ||
745 	    dbus_message_iter_get_element_type (&iter) != DBUS_TYPE_BYTE) {
746 		printf ("expecting an array of byte entries\n");
747 		dbus_message_unref (message);
748 		dbus_message_unref (reply);
749 		return NULL;
750 	}
751 	dbus_message_iter_recurse (&iter, &subiter);
752 
753 	count = 0;
754 	bufsize = 256;
755 	buf = (uchar_t *)malloc (bufsize);
756 
757 	while (dbus_message_iter_get_arg_type (&subiter) == DBUS_TYPE_BYTE) {
758 		if (count == bufsize) {
759 			bufsize += 256;
760 			buf = realloc (buf, bufsize);
761 			if (buf == NULL) {
762 				dbus_message_unref (message);
763 				dbus_message_unref (reply);
764 				return NULL;
765 			}
766 		}
767 
768 		dbus_message_iter_get_basic (&subiter, &value);
769 		buf[count++] = value;
770 		dbus_message_iter_next(&subiter);
771 	}
772 
773 	dbus_message_unref (message);
774 	dbus_message_unref (reply);
775 
776 	*data_size = count;
777 	if (count == 0) {
778 		free (buf);
779 		buf = NULL;
780 	}
781 
782 	return (adt_export_data_t *)buf;
783 }
784 
785 void
786 audit_volume(const adt_export_data_t *imported_state, au_event_t event_id,
787     int result, const char *auth_used, const char *mount_point,
788     const char *device, const char *options)
789 {
790 	adt_session_data_t      *ah;
791 	adt_event_data_t        *event;
792 
793 	if (adt_start_session(&ah, imported_state, 0) != 0) {
794         	printf ("adt_start_session failed %d\n", errno);
795         	return;
796 	}
797 	if ((event = adt_alloc_event(ah, event_id)) == NULL) {
798         	printf ("adt_alloc_event(ADT_attach)\n", errno);
799         	return;
800 	}
801 
802 	switch (event_id) {
803 	case ADT_attach:
804 		event->adt_attach.auth_used = (char *)auth_used;
805 		event->adt_attach.mount_point = (char *)mount_point;
806 		event->adt_attach.device = (char *)device;
807 		event->adt_attach.options = (char *)options;
808 		break;
809 	case ADT_detach:
810 		event->adt_detach.auth_used = (char *)auth_used;
811 		event->adt_detach.mount_point = (char *)mount_point;
812 		event->adt_detach.device = (char *)device;
813 		event->adt_detach.options = (char *)options;
814 		break;
815 	case ADT_remove:
816 		event->adt_remove.auth_used = (char *)auth_used;
817 		event->adt_remove.mount_point = (char *)mount_point;
818 		event->adt_remove.device = (char *)device;
819 		break;
820 	default:
821 		goto out;
822 	}
823 
824 	if (result == 0) {
825 		if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0) {
826 			printf ("adt_put_event(%d, success)\n", event_id);
827 		}
828 	} else {
829 		if (adt_put_event(event, ADT_FAILURE, result) != 0) {
830 			printf ("adt_put_event(%d, failure)\n", event_id);
831 		}
832 	}
833 out:
834 	adt_free_event(event);
835 	(void) adt_end_session(ah);
836 }
837 
838 #endif /* sun */
839