xref: /illumos-gate/usr/src/cmd/hal/tools/hal-storage-mount.c (revision 55fea89dcaa64928bed4327112404dcb3e07b79f)
118c2aff7Sartem /***************************************************************************
218c2aff7Sartem  * CVSID: $Id$
318c2aff7Sartem  *
418c2aff7Sartem  * hal-storage-mount.c : Mount wrapper
518c2aff7Sartem  *
618c2aff7Sartem  * Copyright (C) 2006 David Zeuthen, <david@fubar.dk>
718c2aff7Sartem  *
818c2aff7Sartem  * This program is free software; you can redistribute it and/or modify
918c2aff7Sartem  * it under the terms of the GNU General Public License as published by
1018c2aff7Sartem  * the Free Software Foundation; either version 2 of the License, or
1118c2aff7Sartem  * (at your option) any later version.
1218c2aff7Sartem  *
1318c2aff7Sartem  * This program is distributed in the hope that it will be useful,
1418c2aff7Sartem  * but WITHOUT ANY WARRANTY; without even the implied warranty of
1518c2aff7Sartem  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1618c2aff7Sartem  * GNU General Public License for more details.
1718c2aff7Sartem  *
1818c2aff7Sartem  * You should have received a copy of the GNU General Public License
1918c2aff7Sartem  * along with this program; if not, write to the Free Software
2018c2aff7Sartem  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
2118c2aff7Sartem  *
2218c2aff7Sartem  **************************************************************************/
2318c2aff7Sartem 
2418c2aff7Sartem 
2518c2aff7Sartem #ifdef HAVE_CONFIG_H
2618c2aff7Sartem #  include <config.h>
2718c2aff7Sartem #endif
2818c2aff7Sartem 
2918c2aff7Sartem #include <stdio.h>
3018c2aff7Sartem #include <stdlib.h>
3118c2aff7Sartem #include <string.h>
3218c2aff7Sartem #include <glib.h>
3318c2aff7Sartem #include <glib/gstdio.h>
3418c2aff7Sartem #ifdef __FreeBSD__
3518c2aff7Sartem #include <fstab.h>
3618c2aff7Sartem #include <sys/param.h>
3718c2aff7Sartem #include <sys/ucred.h>
3818c2aff7Sartem #include <sys/mount.h>
3918c2aff7Sartem #include <limits.h>
4018c2aff7Sartem #include <pwd.h>
4118c2aff7Sartem #elif sun
4218c2aff7Sartem #include <sys/mnttab.h>
4318c2aff7Sartem #include <sys/vfstab.h>
4418c2aff7Sartem #include <sys/wait.h>
4518c2aff7Sartem #else
4618c2aff7Sartem #include <mntent.h>
4718c2aff7Sartem #endif
4818c2aff7Sartem #include <sys/types.h>
4918c2aff7Sartem #include <unistd.h>
5018c2aff7Sartem #include <errno.h>
5118c2aff7Sartem #include <syslog.h>
5218c2aff7Sartem 
5318c2aff7Sartem #include <libhal.h>
5418c2aff7Sartem #include <libhal-storage.h>
5518c2aff7Sartem #ifdef HAVE_POLKIT
5618c2aff7Sartem #include <libpolkit.h>
5718c2aff7Sartem #endif
5818c2aff7Sartem 
5918c2aff7Sartem #include "hal-storage-shared.h"
6018c2aff7Sartem 
6118c2aff7Sartem #ifdef __FreeBSD__
6218c2aff7Sartem #define MOUNT		"/sbin/mount"
6318c2aff7Sartem #define MOUNT_OPTIONS	"noexec,nosuid"
6418c2aff7Sartem #define MOUNT_TYPE_OPT	"-t"
6518c2aff7Sartem #elif sun
6618c2aff7Sartem #define MOUNT		"/sbin/mount"
677544909dSartem #define MOUNT_OPTIONS	"nosuid"
6818c2aff7Sartem #define MOUNT_TYPE_OPT	"-F"
6918c2aff7Sartem #else
7018c2aff7Sartem #define MOUNT		"/bin/mount"
7118c2aff7Sartem #define MOUNT_OPTIONS	"noexec,nosuid,nodev"
7218c2aff7Sartem #define MOUNT_TYPE_OPT	"-t"
7318c2aff7Sartem #endif
7418c2aff7Sartem 
7518c2aff7Sartem static void
usage(void)7618c2aff7Sartem usage (void)
7718c2aff7Sartem {
7818c2aff7Sartem 	fprintf (stderr, "This program should only be started by hald.\n");
7918c2aff7Sartem 	exit (1);
8018c2aff7Sartem }
8118c2aff7Sartem 
8218c2aff7Sartem static void
permission_denied_volume_ignore(const char * device)8318c2aff7Sartem permission_denied_volume_ignore (const char *device)
8418c2aff7Sartem {
8518c2aff7Sartem 	fprintf (stderr, "org.freedesktop.Hal.Device.Volume.PermissionDenied\n");
8618c2aff7Sartem 	fprintf (stderr, "Device has %s volume.ignore set to TRUE. Refusing to mount.\n", device);
8718c2aff7Sartem 	exit (1);
8818c2aff7Sartem }
8918c2aff7Sartem 
9018c2aff7Sartem static void
permission_denied_etc_fstab(const char * device)9118c2aff7Sartem permission_denied_etc_fstab (const char *device)
9218c2aff7Sartem {
9318c2aff7Sartem 	fprintf (stderr, "org.freedesktop.Hal.Device.Volume.PermissionDenied\n");
9418c2aff7Sartem 	fprintf (stderr, "Device %s is listed in /etc/fstab. Refusing to mount.\n", device);
9518c2aff7Sartem 	exit (1);
9618c2aff7Sartem }
9718c2aff7Sartem 
9818c2aff7Sartem static void
already_mounted(const char * device)9918c2aff7Sartem already_mounted (const char *device)
10018c2aff7Sartem {
10118c2aff7Sartem 	fprintf (stderr, "org.freedesktop.Hal.Device.Volume.AlreadyMounted\n");
10218c2aff7Sartem 	fprintf (stderr, "Device %s is already mounted.\n", device);
10318c2aff7Sartem 	exit (1);
10418c2aff7Sartem }
10518c2aff7Sartem 
10618c2aff7Sartem static void
invalid_mount_option(const char * option,const char * uid)10718c2aff7Sartem invalid_mount_option (const char *option, const char *uid)
10818c2aff7Sartem {
10918c2aff7Sartem 	fprintf (stderr, "org.freedesktop.Hal.Device.Volume.InvalidMountOption\n");
11018c2aff7Sartem 	fprintf (stderr, "The option '%s' is not allowed for uid=%s\n", option, uid);
11118c2aff7Sartem 	exit (1);
11218c2aff7Sartem }
11318c2aff7Sartem 
11418c2aff7Sartem static void
unknown_filesystem(const char * filesystem)11518c2aff7Sartem unknown_filesystem (const char *filesystem)
11618c2aff7Sartem {
11718c2aff7Sartem 	fprintf (stderr, "org.freedesktop.Hal.Device.Volume.UnknownFilesystemType\n");
11818c2aff7Sartem 	fprintf (stderr, "Unknown file system '%s'\n", filesystem);
11918c2aff7Sartem 	exit (1);
12018c2aff7Sartem }
12118c2aff7Sartem 
12218c2aff7Sartem static void
invalid_mount_point(const char * mount_point)12318c2aff7Sartem invalid_mount_point (const char *mount_point)
12418c2aff7Sartem {
12518c2aff7Sartem 	fprintf (stderr, "org.freedesktop.Hal.Device.Volume.InvalidMountpoint\n");
12618c2aff7Sartem 	fprintf (stderr, "The mount point '%s' is invalid\n", mount_point);
12718c2aff7Sartem 	exit (1);
12818c2aff7Sartem }
12918c2aff7Sartem 
13018c2aff7Sartem static void
mount_point_not_available(const char * mount_point)13118c2aff7Sartem mount_point_not_available (const char *mount_point)
13218c2aff7Sartem {
13318c2aff7Sartem 	fprintf (stderr, "org.freedesktop.Hal.Device.Volume.MountPointNotAvailable\n");
13418c2aff7Sartem 	fprintf (stderr, "The mount point '%s' is already occupied\n", mount_point);
13518c2aff7Sartem 	exit (1);
13618c2aff7Sartem }
13718c2aff7Sartem 
13818c2aff7Sartem 
13918c2aff7Sartem static void
cannot_remount(const char * device)14018c2aff7Sartem cannot_remount (const char *device)
14118c2aff7Sartem {
14218c2aff7Sartem 	fprintf (stderr, "org.freedesktop.Hal.Device.Volume.CannotRemount\n");
14318c2aff7Sartem 	fprintf (stderr, "%s not mounted already\n", device);
14418c2aff7Sartem 	exit (1);
14518c2aff7Sartem }
14618c2aff7Sartem 
14718c2aff7Sartem #ifdef HAVE_POLKIT
14818c2aff7Sartem static void
permission_denied_privilege(const char * privilege,const char * uid)14918c2aff7Sartem permission_denied_privilege (const char *privilege, const char *uid)
15018c2aff7Sartem {
15118c2aff7Sartem 	fprintf (stderr, "org.freedesktop.Hal.Device.PermissionDeniedByPolicy\n");
15218c2aff7Sartem 	fprintf (stderr, "%s refused uid %s\n", privilege, uid);
15318c2aff7Sartem 	exit (1);
15418c2aff7Sartem }
15518c2aff7Sartem #endif
15618c2aff7Sartem 
15718c2aff7Sartem 
15818c2aff7Sartem /* borrowed from gtk/gtkfilesystemunix.c in GTK+ on 02/23/2006 */
15918c2aff7Sartem static void
canonicalize_filename(gchar * filename)16018c2aff7Sartem canonicalize_filename (gchar *filename)
16118c2aff7Sartem {
16218c2aff7Sartem 	gchar *p, *q;
16318c2aff7Sartem 	gboolean last_was_slash = FALSE;
16418c2aff7Sartem 
16518c2aff7Sartem 	p = filename;
16618c2aff7Sartem 	q = filename;
16718c2aff7Sartem 
16818c2aff7Sartem 	while (*p)
16918c2aff7Sartem 	{
17018c2aff7Sartem 		if (*p == G_DIR_SEPARATOR)
17118c2aff7Sartem 		{
17218c2aff7Sartem 			if (!last_was_slash)
17318c2aff7Sartem 				*q++ = G_DIR_SEPARATOR;
17418c2aff7Sartem 
17518c2aff7Sartem 			last_was_slash = TRUE;
17618c2aff7Sartem 		}
17718c2aff7Sartem 		else
17818c2aff7Sartem 		{
17918c2aff7Sartem 			if (last_was_slash && *p == '.')
18018c2aff7Sartem 			{
18118c2aff7Sartem 				if (*(p + 1) == G_DIR_SEPARATOR ||
18218c2aff7Sartem 				    *(p + 1) == '\0')
18318c2aff7Sartem 				{
18418c2aff7Sartem 					if (*(p + 1) == '\0')
18518c2aff7Sartem 						break;
18618c2aff7Sartem 
18718c2aff7Sartem 					p += 1;
18818c2aff7Sartem 				}
18918c2aff7Sartem 				else if (*(p + 1) == '.' &&
19018c2aff7Sartem 					 (*(p + 2) == G_DIR_SEPARATOR ||
19118c2aff7Sartem 					  *(p + 2) == '\0'))
19218c2aff7Sartem 				{
19318c2aff7Sartem 					if (q > filename + 1)
19418c2aff7Sartem 					{
19518c2aff7Sartem 						q--;
19618c2aff7Sartem 						while (q > filename + 1 &&
19718c2aff7Sartem 						       *(q - 1) != G_DIR_SEPARATOR)
19818c2aff7Sartem 							q--;
19918c2aff7Sartem 					}
20018c2aff7Sartem 
20118c2aff7Sartem 					if (*(p + 2) == '\0')
20218c2aff7Sartem 						break;
20318c2aff7Sartem 
20418c2aff7Sartem 					p += 2;
20518c2aff7Sartem 				}
20618c2aff7Sartem 				else
20718c2aff7Sartem 				{
20818c2aff7Sartem 					*q++ = *p;
20918c2aff7Sartem 					last_was_slash = FALSE;
21018c2aff7Sartem 				}
21118c2aff7Sartem 			}
21218c2aff7Sartem 			else
21318c2aff7Sartem 			{
21418c2aff7Sartem 				*q++ = *p;
21518c2aff7Sartem 				last_was_slash = FALSE;
21618c2aff7Sartem 			}
21718c2aff7Sartem 		}
21818c2aff7Sartem 
21918c2aff7Sartem 		p++;
22018c2aff7Sartem 	}
22118c2aff7Sartem 
22218c2aff7Sartem 	if (q > filename + 1 && *(q - 1) == G_DIR_SEPARATOR)
22318c2aff7Sartem 		q--;
22418c2aff7Sartem 
22518c2aff7Sartem 	*q = '\0';
22618c2aff7Sartem }
22718c2aff7Sartem 
22818c2aff7Sartem static char *
resolve_symlink(const char * file)22918c2aff7Sartem resolve_symlink (const char *file)
23018c2aff7Sartem {
231*b877e47fSAlexander Pyhalov 	GError *error = NULL;
23218c2aff7Sartem 	char *dir;
23318c2aff7Sartem 	char *link;
23418c2aff7Sartem 	char *f;
23518c2aff7Sartem 	char *f1;
23618c2aff7Sartem 
23718c2aff7Sartem 	f = g_strdup (file);
23818c2aff7Sartem 
23918c2aff7Sartem 	while (g_file_test (f, G_FILE_TEST_IS_SYMLINK)) {
24018c2aff7Sartem 		link = g_file_read_link (f, &error);
24118c2aff7Sartem 		if (link == NULL) {
24218c2aff7Sartem 			g_warning ("Cannot resolve symlink %s: %s", f, error->message);
24318c2aff7Sartem 			g_error_free (error);
24418c2aff7Sartem 			g_free (f);
24518c2aff7Sartem 			f = NULL;
24618c2aff7Sartem 			goto out;
24718c2aff7Sartem 		}
24818c2aff7Sartem 
24918c2aff7Sartem 		dir = g_path_get_dirname (f);
25018c2aff7Sartem 		f1 = g_strdup_printf ("%s/%s", dir, link);
25118c2aff7Sartem 		g_free (dir);
25218c2aff7Sartem 		g_free (link);
25318c2aff7Sartem 		g_free (f);
25418c2aff7Sartem 		f = f1;
25518c2aff7Sartem 	}
25618c2aff7Sartem 
25718c2aff7Sartem out:
25818c2aff7Sartem 	if (f != NULL)
25918c2aff7Sartem 		canonicalize_filename (f);
26018c2aff7Sartem 	return f;
26118c2aff7Sartem }
26218c2aff7Sartem 
26318c2aff7Sartem static LibHalVolume *
volume_findby(LibHalContext * hal_ctx,const char * property,const char * value)26418c2aff7Sartem volume_findby (LibHalContext *hal_ctx, const char *property, const char *value)
26518c2aff7Sartem {
26618c2aff7Sartem 	int i;
26718c2aff7Sartem 	char **hal_udis;
26818c2aff7Sartem 	int num_hal_udis;
26918c2aff7Sartem 	LibHalVolume *result = NULL;
27018c2aff7Sartem 	char *found_udi = NULL;
27118c2aff7Sartem 	DBusError error;
27218c2aff7Sartem 
27318c2aff7Sartem 	dbus_error_init (&error);
27418c2aff7Sartem 	if ((hal_udis = libhal_manager_find_device_string_match (hal_ctx, property,
27518c2aff7Sartem 								 value, &num_hal_udis, &error)) == NULL) {
27618c2aff7Sartem 		LIBHAL_FREE_DBUS_ERROR (&error);
27718c2aff7Sartem 		goto out;
27818c2aff7Sartem 	}
27918c2aff7Sartem 	for (i = 0; i < num_hal_udis; i++) {
28018c2aff7Sartem 		char *udi;
28118c2aff7Sartem 		udi = hal_udis[i];
28218c2aff7Sartem 		if (libhal_device_query_capability (hal_ctx, udi, "volume", &error)) {
28318c2aff7Sartem 			found_udi = strdup (udi);
28418c2aff7Sartem 			break;
28518c2aff7Sartem 		}
28618c2aff7Sartem 	}
28718c2aff7Sartem 
28818c2aff7Sartem 	libhal_free_string_array (hal_udis);
28918c2aff7Sartem 
29018c2aff7Sartem 	if (found_udi != NULL)
29118c2aff7Sartem 		result = libhal_volume_from_udi (hal_ctx, found_udi);
29218c2aff7Sartem 
29318c2aff7Sartem 	free (found_udi);
29418c2aff7Sartem out:
29518c2aff7Sartem 	return result;
29618c2aff7Sartem }
29718c2aff7Sartem 
29818c2aff7Sartem static void
bailout_if_in_fstab(LibHalContext * hal_ctx,const char * device,const char * label,const char * uuid)29918c2aff7Sartem bailout_if_in_fstab (LibHalContext *hal_ctx, const char *device, const char *label, const char *uuid)
30018c2aff7Sartem {
30118c2aff7Sartem 	gpointer handle;
30218c2aff7Sartem 	char *entry;
30318c2aff7Sartem 	char *_mount_point;
30418c2aff7Sartem 
30518c2aff7Sartem 	printf (" label '%s'  uuid '%s'\n", label ? label : "" , uuid ? uuid : "");
30618c2aff7Sartem 
30718c2aff7Sartem 	/* check if /etc/fstab mentions this device... (with symlinks etc) */
30818c2aff7Sartem 	if (! fstab_open (&handle)) {
30918c2aff7Sartem 		printf ("cannot open /etc/fstab\n");
31018c2aff7Sartem 		unknown_error ("Cannot open /etc/fstab");
31118c2aff7Sartem 	}
31218c2aff7Sartem 	while ((entry = fstab_next (handle, &_mount_point)) != NULL) {
31318c2aff7Sartem 		char *resolved;
31418c2aff7Sartem 
31518c2aff7Sartem #ifdef DEBUG
31618c2aff7Sartem 		printf ("Looking at /etc/fstab entry '%s'\n", entry);
31718c2aff7Sartem #endif
31818c2aff7Sartem 		if (label != NULL && g_str_has_prefix (entry, "LABEL=")) {
31918c2aff7Sartem 			if (strcmp (entry + 6, label) == 0) {
32018c2aff7Sartem 				gboolean skip_fstab_entry;
32118c2aff7Sartem 
32218c2aff7Sartem 				skip_fstab_entry = FALSE;
32318c2aff7Sartem 
32418c2aff7Sartem 				/* (heck, we also do the stuff below in gnome-mount) */
32518c2aff7Sartem 
32618c2aff7Sartem 				/* OK, so what's if someone attaches an external disk with the label '/' and
32718c2aff7Sartem 				 * /etc/fstab has
32818c2aff7Sartem 				 *
32918c2aff7Sartem 				 *    LABEL=/    /    ext3    defaults    1 1
33018c2aff7Sartem 				 *
33118c2aff7Sartem 				 * in /etc/fstab as most Red Hat systems do? Bugger, this is a very common use
33218c2aff7Sartem 				 * case; suppose that you take the disk from your Fedora server and attaches it
33318c2aff7Sartem 				 * to your laptop. Bingo, you now have two disks with the label '/'. One must
33418c2aff7Sartem 				 * seriously wonder if using things like LABEL=/ for / is a good idea; just
33518c2aff7Sartem 				 * what happens if you boot in this configuration? (answer: the initrd gets
33618c2aff7Sartem 				 * it wrong most of the time.. sigh)
33718c2aff7Sartem 				 *
33818c2aff7Sartem 				 * To work around this, check if the listed entry in /etc/fstab is already mounted,
33918c2aff7Sartem 				 * if it is, then check if it's the same device_file as the given one...
34018c2aff7Sartem 				 */
34118c2aff7Sartem 
34218c2aff7Sartem 				/* see if a volume is mounted at this mount point  */
34318c2aff7Sartem 				if (_mount_point != NULL) {
34418c2aff7Sartem 					LibHalVolume *mounted_vol;
34518c2aff7Sartem 
34618c2aff7Sartem 					mounted_vol = volume_findby (hal_ctx, "volume.mount_point", _mount_point);
34718c2aff7Sartem 					if (mounted_vol != NULL) {
34818c2aff7Sartem 						const char *mounted_vol_device_file;
34918c2aff7Sartem 
35018c2aff7Sartem 						mounted_vol_device_file = libhal_volume_get_device_file (mounted_vol);
35118c2aff7Sartem 						/* no need to resolve symlinks, hal uses the canonical device file */
35218c2aff7Sartem 						if (mounted_vol_device_file != NULL &&
35318c2aff7Sartem 						    strcmp (mounted_vol_device_file, device) !=0) {
35418c2aff7Sartem #ifdef DEBUG
35518c2aff7Sartem 							printf ("Wanting to mount %s that has label %s, but /etc/fstab says LABEL=%s is to be mounted at mount point '%s'. However %s (that also has label %s), is already mounted at said mount point. So, skipping said /etc/fstab entry.\n",
35618c2aff7Sartem 								   device, label, label, _mount_point, mounted_vol_device_file, _mount_point);
35718c2aff7Sartem #endif
35818c2aff7Sartem 							skip_fstab_entry = TRUE;
35918c2aff7Sartem 						}
36018c2aff7Sartem 						libhal_volume_free (mounted_vol);
36118c2aff7Sartem 					}
36218c2aff7Sartem 				}
36318c2aff7Sartem 
36418c2aff7Sartem 				if (!skip_fstab_entry) {
36518c2aff7Sartem 					printf ("%s found in /etc/fstab. Not mounting.\n", entry);
36618c2aff7Sartem 					permission_denied_etc_fstab (device);
36718c2aff7Sartem 				}
36818c2aff7Sartem 			}
36918c2aff7Sartem 		} else if (uuid != NULL && g_str_has_prefix (entry, "UUID=")) {
37018c2aff7Sartem 			if (strcmp (entry + 5, uuid) == 0) {
37118c2aff7Sartem 				printf ("%s found in /etc/fstab. Not mounting.\n", entry);
37218c2aff7Sartem 				permission_denied_etc_fstab (device);
37318c2aff7Sartem 			}
37418c2aff7Sartem 		} else {
37518c2aff7Sartem 
37618c2aff7Sartem 			resolved = resolve_symlink (entry);
37718c2aff7Sartem #ifdef DEBUG
37818c2aff7Sartem 			printf ("/etc/fstab: device %s -> %s \n", entry, resolved);
37918c2aff7Sartem #endif
38018c2aff7Sartem 			if (strcmp (device, resolved) == 0) {
38118c2aff7Sartem 				printf ("%s (-> %s) found in /etc/fstab. Not mounting.\n", entry, resolved);
38218c2aff7Sartem 				permission_denied_etc_fstab (device);
38318c2aff7Sartem 			}
38418c2aff7Sartem 
38518c2aff7Sartem 			g_free (resolved);
38618c2aff7Sartem 		}
38718c2aff7Sartem 	}
38818c2aff7Sartem 	fstab_close (handle);
38918c2aff7Sartem }
39018c2aff7Sartem 
39118c2aff7Sartem static gboolean
device_is_mounted(const char * device,char ** mount_point)39218c2aff7Sartem device_is_mounted (const char *device, char **mount_point)
39318c2aff7Sartem {
39418c2aff7Sartem 	gpointer handle;
39518c2aff7Sartem 	char *entry;
39618c2aff7Sartem 	gboolean ret;
39718c2aff7Sartem 
39818c2aff7Sartem 	ret = FALSE;
39918c2aff7Sartem 
40018c2aff7Sartem 	/* check if /proc/mounts mentions this device... (with symlinks etc) */
40118c2aff7Sartem 	if (! mtab_open (&handle)) {
40218c2aff7Sartem 		printf ("cannot open mount list\n");
40318c2aff7Sartem 		unknown_error ("Cannot open /etc/mtab or equivalent");
40418c2aff7Sartem 	}
40518c2aff7Sartem 	while (((entry = mtab_next (handle, mount_point)) != NULL) && (ret == FALSE)) {
40618c2aff7Sartem 		char *resolved;
40718c2aff7Sartem 
40818c2aff7Sartem 		resolved = resolve_symlink (entry);
40918c2aff7Sartem #ifdef DEBUG
41018c2aff7Sartem 		printf ("/proc/mounts: device %s -> %s \n", entry, resolved);
41118c2aff7Sartem #endif
41218c2aff7Sartem 		if (strcmp (device, resolved) == 0) {
41318c2aff7Sartem 			printf ("%s (-> %s) found in mount list. Not mounting.\n", entry, resolved);
41418c2aff7Sartem 			ret = TRUE;
41518c2aff7Sartem 		}
41618c2aff7Sartem 
41718c2aff7Sartem 		g_free (resolved);
41818c2aff7Sartem 	}
41918c2aff7Sartem 	mtab_close (handle);
42018c2aff7Sartem 	return ret;
42118c2aff7Sartem }
42218c2aff7Sartem 
42318c2aff7Sartem /* maps volume_id fs types to the appropriate -t mount option */
42418c2aff7Sartem static const char *
map_fstype(const char * fstype)42518c2aff7Sartem map_fstype (const char *fstype)
42618c2aff7Sartem {
42718c2aff7Sartem #ifdef __FreeBSD__
42818c2aff7Sartem 	if (! strcmp (fstype, "iso9660"))
42918c2aff7Sartem 		return "cd9660";
43018c2aff7Sartem 	else if (! strcmp (fstype, "ext2"))
43118c2aff7Sartem 		return "ext2fs";
43218c2aff7Sartem 	else if (! strcmp (fstype, "vfat"))
43318c2aff7Sartem 		return "msdosfs";
43418c2aff7Sartem #elif sun
43518c2aff7Sartem 	if (! strcmp (fstype, "iso9660"))
43618c2aff7Sartem 		return "hsfs";
43718c2aff7Sartem 	else if (! strcmp (fstype, "vfat"))
43818c2aff7Sartem 		return "pcfs";
43918c2aff7Sartem #endif
44018c2aff7Sartem 
44118c2aff7Sartem 	return fstype;
44218c2aff7Sartem }
44318c2aff7Sartem 
44418c2aff7Sartem static void
handle_mount(LibHalContext * hal_ctx,LibPolKitContext * pol_ctx,const char * udi,LibHalVolume * volume,LibHalDrive * drive,const char * device,const char * invoked_by_uid,const char * invoked_by_syscon_name,DBusConnection * system_bus)44518c2aff7Sartem handle_mount (LibHalContext *hal_ctx,
44618c2aff7Sartem #ifdef HAVE_POLKIT
44718c2aff7Sartem 	      LibPolKitContext *pol_ctx,
44818c2aff7Sartem #endif
44918c2aff7Sartem 	      const char *udi,
45018c2aff7Sartem 	      LibHalVolume *volume, LibHalDrive *drive, const char *device,
45118c2aff7Sartem 	      const char *invoked_by_uid, const char *invoked_by_syscon_name,
45218c2aff7Sartem 	      DBusConnection *system_bus)
45318c2aff7Sartem {
45418c2aff7Sartem 	int i, j;
45518c2aff7Sartem 	DBusError error;
45618c2aff7Sartem 	char mount_point[256];
45718c2aff7Sartem 	char mount_fstype[256];
45818c2aff7Sartem 	char mount_options[1024];
45918c2aff7Sartem 	char **allowed_options;
46018c2aff7Sartem 	char **given_options;
46118c2aff7Sartem 	gboolean wants_to_change_uid;
46218c2aff7Sartem 	char *mount_dir;
46318c2aff7Sartem 	GError *err = NULL;
46418c2aff7Sartem 	char *sout = NULL;
46518c2aff7Sartem 	char *serr = NULL;
46618c2aff7Sartem 	int exit_status;
46718c2aff7Sartem 	char *args[10];
46818c2aff7Sartem 	int na;
46918c2aff7Sartem 	GString *mount_option_str;
47018c2aff7Sartem 	gboolean pol_is_fixed;
47118c2aff7Sartem 	gboolean pol_change_uid;
47218c2aff7Sartem 	char *privilege;
47318c2aff7Sartem 	gboolean is_remount;
47418c2aff7Sartem #ifdef HAVE_POLKIT
47518c2aff7Sartem 	gboolean allowed_by_privilege;
47618c2aff7Sartem 	gboolean is_temporary_privilege;
47718c2aff7Sartem #endif
47818c2aff7Sartem 	gboolean explicit_mount_point_given;
47918c2aff7Sartem 	const char *end;
48018c2aff7Sartem #ifdef __FreeBSD__
48118c2aff7Sartem 	struct passwd *pw;
48218c2aff7Sartem 	uid_t calling_uid;
48318c2aff7Sartem 	gid_t calling_gid;
48418c2aff7Sartem #endif
48518c2aff7Sartem 	const char *label;
48618c2aff7Sartem 	const char *uuid;
48718c2aff7Sartem 	const char *model;
48818c2aff7Sartem 	const char *drive_type;
48918c2aff7Sartem #ifdef sun
49018c2aff7Sartem 	adt_export_data_t *adt_data;
49118c2aff7Sartem 	size_t adt_data_size;
49218c2aff7Sartem 	gboolean append_ro = FALSE;
49318c2aff7Sartem 	gboolean is_abs_path = FALSE;
49418c2aff7Sartem 	uid_t calling_uid;
49518c2aff7Sartem 
49618c2aff7Sartem 	calling_uid = atol (invoked_by_uid);
49718c2aff7Sartem #endif
49818c2aff7Sartem 
49918c2aff7Sartem #ifdef DEBUG
50018c2aff7Sartem 	printf ("device                           = %s\n", device);
50118c2aff7Sartem 	printf ("invoked by uid                   = %s\n", invoked_by_uid);
50218c2aff7Sartem 	printf ("invoked by system bus connection = %s\n", invoked_by_syscon_name);
50318c2aff7Sartem #endif
50418c2aff7Sartem 
50518c2aff7Sartem 	if (volume != NULL) {
50618c2aff7Sartem 		dbus_error_init (&error);
50718c2aff7Sartem 		if (libhal_device_get_property_bool (hal_ctx, udi, "volume.ignore", &error) ||
50818c2aff7Sartem 		    dbus_error_is_set (&error)) {
50918c2aff7Sartem 			if (dbus_error_is_set (&error)) {
51018c2aff7Sartem 				LIBHAL_FREE_DBUS_ERROR (&error);
51118c2aff7Sartem 			}
51218c2aff7Sartem 			/*
51318c2aff7Sartem 			 * When device allocation is enabled (bsmconv or TX), we
51418c2aff7Sartem 			 * set volume.ignore on all volumes, but still want
51518c2aff7Sartem 			 * Mount() to succeed when called from the euid=0
51618c2aff7Sartem 			 * device allocation program.
51718c2aff7Sartem 			 */
51818c2aff7Sartem 			if (atol (invoked_by_uid) != 0) {
51918c2aff7Sartem 				permission_denied_volume_ignore (device);
52018c2aff7Sartem 			}
52118c2aff7Sartem 		}
52218c2aff7Sartem 
52318c2aff7Sartem 		label = libhal_volume_get_label (volume);
52418c2aff7Sartem 		uuid = libhal_volume_get_uuid (volume);
52518c2aff7Sartem 	} else {
52618c2aff7Sartem 		label = NULL;
52718c2aff7Sartem 		uuid = NULL;
52818c2aff7Sartem 	}
52918c2aff7Sartem 
53018c2aff7Sartem 	bailout_if_in_fstab (hal_ctx, device, label, uuid);
53118c2aff7Sartem 
53218c2aff7Sartem 	/* TODO: sanity check that what hal exports is correct (cf. Martin Pitt's email) */
53318c2aff7Sartem 
53418c2aff7Sartem 	/* read from stdin */
53518c2aff7Sartem 	if (strlen (fgets (mount_point, sizeof (mount_point), stdin)) > 0)
53618c2aff7Sartem 		mount_point   [strlen (mount_point)   - 1] = '\0';
53718c2aff7Sartem 	if (strlen (fgets (mount_fstype, sizeof (mount_fstype), stdin)) > 0)
53818c2aff7Sartem 		mount_fstype  [strlen (mount_fstype)  - 1] = '\0';
53918c2aff7Sartem 	if (strlen (fgets (mount_options, sizeof (mount_options), stdin)) > 0)
54018c2aff7Sartem 		mount_options [strlen (mount_options) - 1] = '\0';
54118c2aff7Sartem 	/* validate that input from stdin is UTF-8 */
54218c2aff7Sartem 	if (!g_utf8_validate (mount_point, -1, &end))
54318c2aff7Sartem 		unknown_error ("Error validating mount_point as UTF-8");
54418c2aff7Sartem 	if (!g_utf8_validate (mount_fstype, -1, &end))
54518c2aff7Sartem 		unknown_error ("Error validating mount_fstype as UTF-8");
54618c2aff7Sartem 	if (!g_utf8_validate (mount_options, -1, &end))
54718c2aff7Sartem 		unknown_error ("Error validating mount_options as UTF-8");
54818c2aff7Sartem 
54918c2aff7Sartem #ifdef sun
55018c2aff7Sartem 	if (calling_uid != 0) {
55118c2aff7Sartem #endif
55218c2aff7Sartem 	for (i = 0; mount_point[i] != '\0'; i++) {
55318c2aff7Sartem 		if (mount_point[i] == '\n' ||
55418c2aff7Sartem 		    mount_point[i] == G_DIR_SEPARATOR) {
55518c2aff7Sartem 			unknown_error ("mount_point cannot contain the following characters: newline, G_DIR_SEPARATOR (usually /)");
55618c2aff7Sartem 		}
55718c2aff7Sartem 	}
55818c2aff7Sartem #ifdef sun
55918c2aff7Sartem 	}
56018c2aff7Sartem 	is_abs_path = (mount_point[0] == G_DIR_SEPARATOR);
56118c2aff7Sartem #endif
56218c2aff7Sartem 
56318c2aff7Sartem #ifdef DEBUG
56418c2aff7Sartem 	printf ("mount_point    = '%s'\n", mount_point);
56518c2aff7Sartem 	printf ("mount_fstype   = '%s'\n", mount_fstype);
56618c2aff7Sartem 	printf ("mount_options  = '%s'\n", mount_options);
56718c2aff7Sartem #endif
56818c2aff7Sartem 
56918c2aff7Sartem 	/* delete any trailing whitespace options from splitting the string */
57018c2aff7Sartem 	given_options = g_strsplit (mount_options, "\t", 0);
57118c2aff7Sartem 	for (i = g_strv_length (given_options) - 1; i >= 0; --i) {
57218c2aff7Sartem 		if (strlen (given_options[i]) > 0)
57318c2aff7Sartem 			break;
57418c2aff7Sartem 		given_options[i] = NULL;
57518c2aff7Sartem 	}
57618c2aff7Sartem 
57718c2aff7Sartem #ifdef sun
57818c2aff7Sartem 	/* for read-only media append 'ro' option if not already */
57918c2aff7Sartem 	append_ro = libhal_device_get_property_bool (hal_ctx, libhal_drive_get_udi(drive),
58018c2aff7Sartem 	    "storage.removable.solaris.read_only", NULL);
58118c2aff7Sartem 
58218c2aff7Sartem 	if (append_ro) {
58318c2aff7Sartem 		for (i = 0; i < (int) g_strv_length (given_options); i++) {
58418c2aff7Sartem 			if (strcmp (given_options[i], "ro") == 0) {
58518c2aff7Sartem 				append_ro = FALSE;
58618c2aff7Sartem 			}
58718c2aff7Sartem 		}
58818c2aff7Sartem 	}
58918c2aff7Sartem #endif /* sun */
59018c2aff7Sartem 
59118c2aff7Sartem 	/* is option 'remount' included? */
59218c2aff7Sartem 	is_remount = FALSE;
59318c2aff7Sartem 	for (i = 0; i < (int) g_strv_length (given_options); i++) {
59418c2aff7Sartem 		if (strcmp (given_options[i], "remount") == 0) {
59518c2aff7Sartem 			is_remount = TRUE;
59618c2aff7Sartem 		}
59718c2aff7Sartem 	}
59818c2aff7Sartem 
59918c2aff7Sartem 	mount_dir = NULL;
60018c2aff7Sartem 	if (is_remount) {
60118c2aff7Sartem 		if (volume != NULL) {
60218c2aff7Sartem 			if (!libhal_volume_is_mounted (volume)) {
60318c2aff7Sartem 				cannot_remount (device);
60418c2aff7Sartem 			}
60518c2aff7Sartem 			mount_dir = g_strdup (libhal_volume_get_mount_point (volume));
60618c2aff7Sartem 		} else {
60718c2aff7Sartem 			if (!device_is_mounted (device, &mount_dir)) {
60818c2aff7Sartem 				cannot_remount (device);
60918c2aff7Sartem 			}
61018c2aff7Sartem 		}
61118c2aff7Sartem 
61218c2aff7Sartem 		if (mount_dir == NULL) {
61318c2aff7Sartem 			unknown_error ("Cannot get mount_dir for remount even though volume is mounted!");
61418c2aff7Sartem 		}
61518c2aff7Sartem 
61618c2aff7Sartem 	} else {
61718c2aff7Sartem 		if (volume != NULL) {
61818c2aff7Sartem 			if (libhal_volume_is_mounted (volume)) {
61918c2aff7Sartem 				already_mounted (device);
62018c2aff7Sartem 			}
62118c2aff7Sartem 		} else {
62218c2aff7Sartem 			if (device_is_mounted (device, NULL)) {
62318c2aff7Sartem 				already_mounted (device);
62418c2aff7Sartem 			}
62518c2aff7Sartem 		}
62618c2aff7Sartem 	}
62718c2aff7Sartem 
62818c2aff7Sartem 	if (!is_remount) {
62918c2aff7Sartem 		/* figure out mount point if no mount point is given... */
63018c2aff7Sartem 		explicit_mount_point_given = FALSE;
63118c2aff7Sartem 		if (strlen (mount_point) == 0) {
63218c2aff7Sartem 			char *p;
63318c2aff7Sartem 			const char *label;
63418c2aff7Sartem 
63518c2aff7Sartem 			if (volume != NULL)
63618c2aff7Sartem 				label = libhal_volume_get_label (volume);
63718c2aff7Sartem 			else
63818c2aff7Sartem 				label = NULL;
63918c2aff7Sartem 
64018c2aff7Sartem 			model = libhal_drive_get_model (drive);
64118c2aff7Sartem 			drive_type = libhal_drive_get_type_textual (drive);
64218c2aff7Sartem 
64318c2aff7Sartem 			if (label != NULL) {
64418c2aff7Sartem 				/* best - use label */
64518c2aff7Sartem 				g_strlcpy (mount_point, label, sizeof (mount_point));
64618c2aff7Sartem 
64718c2aff7Sartem 			} else if ((model != NULL) && (strlen (model) > 0)) {
64818c2aff7Sartem 				g_strlcpy (mount_point, model, sizeof (mount_point));
64918c2aff7Sartem 			} else if ((drive_type != NULL) && (strlen (drive_type) > 0)) {
65018c2aff7Sartem 				g_strlcpy (mount_point, drive_type, sizeof (mount_point));
65118c2aff7Sartem 			} else {
65218c2aff7Sartem 				/* fallback - use "disk" */
65318c2aff7Sartem 				g_snprintf (mount_point, sizeof (mount_point), "disk");
65418c2aff7Sartem 			}
65518c2aff7Sartem 
65618c2aff7Sartem 			/* sanitize computed mount point name, e.g. replace invalid chars with '-' */
65718c2aff7Sartem 			p = mount_point;
65818c2aff7Sartem 			while (TRUE) {
65918c2aff7Sartem 				p = g_utf8_strchr (mount_point, -1, G_DIR_SEPARATOR);
66018c2aff7Sartem 				if (p == NULL)
66118c2aff7Sartem 					break;
66218c2aff7Sartem 				*p = '-';
66318c2aff7Sartem 			};
66418c2aff7Sartem 
66518c2aff7Sartem 		} else {
66618c2aff7Sartem 			explicit_mount_point_given = TRUE;
66718c2aff7Sartem 		}
66818c2aff7Sartem 
66918c2aff7Sartem 		/* check mount point name - only forbid separators */
67018c2aff7Sartem #ifdef sun
67118c2aff7Sartem 		if (calling_uid != 0) {
67218c2aff7Sartem #endif
67318c2aff7Sartem 		if (g_utf8_strchr (mount_point, -1, G_DIR_SEPARATOR) != NULL) {
67418c2aff7Sartem 			printf ("'%s' is an invalid mount point\n", mount_point);
67518c2aff7Sartem 			invalid_mount_point (mount_point);
67618c2aff7Sartem 		}
67718c2aff7Sartem #ifdef sun
67818c2aff7Sartem 		}
67918c2aff7Sartem #endif
68018c2aff7Sartem 
68118c2aff7Sartem 		/* check if mount point is available - append number to mount point */
68218c2aff7Sartem 		i = 0;
68318c2aff7Sartem 		mount_dir = NULL;
68418c2aff7Sartem 		while (TRUE) {
68518c2aff7Sartem 			g_free (mount_dir);
68618c2aff7Sartem #ifdef sun
68718c2aff7Sartem 			if (is_abs_path)
68818c2aff7Sartem 				mount_dir = g_strdup (mount_point);
68918c2aff7Sartem 			else
69018c2aff7Sartem #endif
69118c2aff7Sartem 			if (i == 0)
69218c2aff7Sartem 				mount_dir = g_strdup_printf ("/media/%s", mount_point);
69318c2aff7Sartem 			else
69418c2aff7Sartem 				mount_dir = g_strdup_printf ("/media/%s-%d", mount_point, i);
69518c2aff7Sartem 
69618c2aff7Sartem #ifdef DEBUG
69718c2aff7Sartem 			printf ("trying dir %s\n", mount_dir);
69818c2aff7Sartem #endif
69918c2aff7Sartem 
70018c2aff7Sartem 			/* XXX should test for being a mount point */
70118c2aff7Sartem 			if (!g_file_test (mount_dir, G_FILE_TEST_EXISTS)) {
70218c2aff7Sartem 				break;
70318c2aff7Sartem 			}
70418c4e255SLin Guo - Sun Microsystems 
70518c2aff7Sartem 			if (explicit_mount_point_given) {
70618c2aff7Sartem 				mount_point_not_available (mount_dir);
70718c2aff7Sartem 			}
70818c2aff7Sartem 
70918c2aff7Sartem 			i++;
71018c2aff7Sartem 		}
71118c2aff7Sartem 	}
71218c2aff7Sartem 
71318c2aff7Sartem 	dbus_error_init (&error);
71418c2aff7Sartem 	allowed_options = libhal_device_get_property_strlist (hal_ctx, udi, "volume.mount.valid_options", &error);
71518c2aff7Sartem 	if (dbus_error_is_set (&error)) {
71618c2aff7Sartem 		unknown_error ("Cannot get volume.mount.valid_options");
71718c2aff7Sartem 		dbus_error_free (&error);
71818c2aff7Sartem 	}
71918c2aff7Sartem 
72018c2aff7Sartem #ifdef DEBUG
72118c2aff7Sartem 	for (i = 0; given_options[i] != NULL; i++)
72218c2aff7Sartem 		printf ("given_options[%d] = '%s'\n", i, given_options[i]);
72318c2aff7Sartem 	for (i = 0; allowed_options[i] != NULL; i++)
72418c2aff7Sartem 		printf ("allowed_options[%d] = '%s'\n", i, allowed_options[i]);
72518c2aff7Sartem #endif
72618c2aff7Sartem 
72718c2aff7Sartem 	wants_to_change_uid = FALSE;
72818c2aff7Sartem 
72918c2aff7Sartem 	/* check mount options */
73018c2aff7Sartem 	for (i = 0; given_options[i] != NULL; i++) {
73118c2aff7Sartem 		char *given = given_options[i];
73218c2aff7Sartem 
73318c2aff7Sartem 		for (j = 0; allowed_options[j] != NULL; j++) {
73418c2aff7Sartem 			char *allow = allowed_options[j];
73518c2aff7Sartem 			int allow_len = strlen (allow);
73618c2aff7Sartem 
73718c2aff7Sartem 			if (strcmp (given, allow) == 0) {
73818c2aff7Sartem 				goto option_ok;
73918c2aff7Sartem 			}
74018c2aff7Sartem 
74118c2aff7Sartem 			if ((allow[allow_len - 1] == '=') &&
74218c2aff7Sartem 			    (strncmp (given, allow, allow_len) == 0) &&
74318c2aff7Sartem 			    (int) strlen (given) > allow_len) {
74418c2aff7Sartem 
74518c2aff7Sartem 				/* option matched allowed ending in '=', e.g.
74618c2aff7Sartem 				 * given == "umask=foobar" and allowed == "umask="
74718c2aff7Sartem 				 */
74818c2aff7Sartem 				if (strcmp (allow, "uid=") == 0) {
74918c2aff7Sartem 					uid_t uid;
75018c2aff7Sartem 					char *endp;
75118c2aff7Sartem 					/* check for uid=, it requires special handling */
75218c2aff7Sartem 					uid = (uid_t) strtol (given + allow_len, &endp, 10);
75318c2aff7Sartem 					if (*endp != '\0') {
75418c2aff7Sartem 						printf ("'%s' is not a number?\n", given);
75518c2aff7Sartem 						unknown_error ("option uid is malformed");
75618c2aff7Sartem 					}
75718c2aff7Sartem #ifdef DEBUG
75818c2aff7Sartem 					printf ("%s with uid %d\n", allow, uid);
75918c2aff7Sartem #endif
76018c2aff7Sartem 					wants_to_change_uid = TRUE;
76118c2aff7Sartem 
76218c2aff7Sartem 					goto option_ok;
76318c2aff7Sartem 				} else {
76418c2aff7Sartem 
76518c2aff7Sartem 					goto option_ok;
76618c2aff7Sartem 				}
76718c2aff7Sartem 			}
76818c2aff7Sartem 		}
76918c2aff7Sartem 
77018c2aff7Sartem 		/* apparently option was not ok */
77118c2aff7Sartem 		invalid_mount_option (given, invoked_by_uid);
77218c2aff7Sartem 
77318c2aff7Sartem 	option_ok:
77418c2aff7Sartem 		;
77518c2aff7Sartem 	}
77618c2aff7Sartem 
77718c2aff7Sartem 	/* Check privilege */
77818c2aff7Sartem 	pol_is_fixed = TRUE;
77918c2aff7Sartem 	if (libhal_drive_is_hotpluggable (drive) || libhal_drive_uses_removable_media (drive))
78018c2aff7Sartem 		pol_is_fixed = FALSE;
78118c2aff7Sartem 
78218c2aff7Sartem 	pol_change_uid = FALSE;
78318c2aff7Sartem 	/* don't consider uid= on non-pollable drives for the purpose of policy
78418c2aff7Sartem 	 * (since these drives normally use vfat)
78518c2aff7Sartem 	 */
78618c2aff7Sartem 	if (volume != NULL) {
78718c2aff7Sartem 		/* don't consider uid= on vfat, iso9660, udf change-uid for the purpose of policy
78818c2aff7Sartem 		 * (since these doesn't contain uid/gid bits)
78918c2aff7Sartem 		 */
79018c2aff7Sartem 		if (strcmp (libhal_volume_get_fstype (volume), "vfat") != 0 &&
79118c2aff7Sartem 		    strcmp (libhal_volume_get_fstype (volume), "iso9660") != 0 &&
79218c2aff7Sartem 		    strcmp (libhal_volume_get_fstype (volume), "udf") != 0) {
79318c2aff7Sartem 			pol_change_uid = wants_to_change_uid;
79418c2aff7Sartem 		}
79518c2aff7Sartem 	}
79618c2aff7Sartem 
79718c2aff7Sartem 	if (pol_is_fixed) {
79818c2aff7Sartem 		if (pol_change_uid) {
79918c2aff7Sartem 			privilege = "hal-storage-fixed-mount-all-options";
80018c2aff7Sartem 		} else {
80118c2aff7Sartem 			privilege = "hal-storage-fixed-mount";
80218c2aff7Sartem 		}
80318c2aff7Sartem 	} else {
80418c2aff7Sartem 		if (pol_change_uid) {
80518c2aff7Sartem 			privilege = "hal-storage-removable-mount-all-options";
80618c2aff7Sartem 		} else {
80718c2aff7Sartem 			privilege = "hal-storage-removable-mount";
80818c2aff7Sartem 		}
80918c2aff7Sartem 	}
81018c2aff7Sartem 
81118c2aff7Sartem #ifdef DEBUG
81218c2aff7Sartem 	printf ("using privilege %s for uid %s, system_bus_connection %s\n", privilege, invoked_by_uid,
81318c2aff7Sartem 		invoked_by_syscon_name);
81418c2aff7Sartem #endif
81518c2aff7Sartem 
81618c2aff7Sartem #ifdef HAVE_POLKIT
81718c2aff7Sartem 	if (libpolkit_is_uid_allowed_for_privilege (pol_ctx,
81818c2aff7Sartem 						    invoked_by_syscon_name,
81918c2aff7Sartem 						    invoked_by_uid,
82018c2aff7Sartem 						    privilege,
82118c2aff7Sartem 						    udi,
82218c2aff7Sartem 						    &allowed_by_privilege,
82318c2aff7Sartem 						    &is_temporary_privilege,
82418c2aff7Sartem 						    NULL) != LIBPOLKIT_RESULT_OK) {
82518c2aff7Sartem 		printf ("cannot lookup privilege\n");
82618c2aff7Sartem 		unknown_error ("Cannot lookup privilege from PolicyKit");
82718c2aff7Sartem 	}
82818c2aff7Sartem 
82918c2aff7Sartem 	if (!allowed_by_privilege) {
83018c2aff7Sartem 		printf ("caller don't possess privilege\n");
83118c2aff7Sartem 		permission_denied_privilege (privilege, invoked_by_uid);
83218c2aff7Sartem 	}
83318c2aff7Sartem #endif
83418c2aff7Sartem 
83518c2aff7Sartem #ifdef DEBUG
83618c2aff7Sartem 	printf ("passed privilege\n");
83718c2aff7Sartem #endif
83818c2aff7Sartem 
83918c2aff7Sartem 	if (!is_remount) {
84018c2aff7Sartem 		/* create directory */
84118c2aff7Sartem #ifdef sun
842b941d3fcSartem 		if (!g_file_test (mount_dir, G_FILE_TEST_EXISTS) &&
843b941d3fcSartem 		    (g_mkdir (mount_dir, 0755) != 0)) {
844b941d3fcSartem #else
84518c2aff7Sartem 		if (g_mkdir (mount_dir, 0700) != 0) {
846b941d3fcSartem #endif
84718c2aff7Sartem 			printf ("Cannot create '%s'\n", mount_dir);
84818c2aff7Sartem 			unknown_error ("Cannot create mount directory");
84918c2aff7Sartem 		}
85018c2aff7Sartem 
85118c2aff7Sartem #ifdef __FreeBSD__
85218c2aff7Sartem 		calling_uid = (uid_t) strtol (invoked_by_uid, (char **) NULL, 10);
85318c2aff7Sartem 		pw = getpwuid (calling_uid);
85418c2aff7Sartem 		if (pw != NULL) {
85518c2aff7Sartem 			calling_gid = pw->pw_gid;
85618c2aff7Sartem 		} else {
85718c2aff7Sartem 			calling_gid = 0;
85818c2aff7Sartem 		}
85918c2aff7Sartem 		if (chown (mount_dir, calling_uid, calling_gid) != 0) {
86018c2aff7Sartem 			printf ("Cannot chown '%s' to uid: %d, gid: %d\n", mount_dir,
86118c2aff7Sartem 				calling_uid, calling_gid);
86218c2aff7Sartem 			g_rmdir (mount_dir);
86318c2aff7Sartem 			unknown_error ();
86418c2aff7Sartem 		}
86518c2aff7Sartem #endif
86618c2aff7Sartem 	}
86718c2aff7Sartem 
86818c2aff7Sartem 	char *mount_option_commasep = NULL;
86918c2aff7Sartem 	char *mount_do_fstype = "auto";
87018c2aff7Sartem 
87118c2aff7Sartem 	/* construct arguments to mount */
87218c2aff7Sartem 	na = 0;
87318c2aff7Sartem 	args[na++] = MOUNT;
87418c2aff7Sartem 	if (strlen (mount_fstype) > 0) {
87518c2aff7Sartem 		mount_do_fstype = (char *) map_fstype (mount_fstype);
87618c2aff7Sartem 	} else if (volume == NULL) {
87718c2aff7Sartem 		/* non-pollable drive; force auto */
87818c2aff7Sartem 		mount_do_fstype = "auto";
87918c2aff7Sartem 	} else if (libhal_volume_get_fstype (volume) != NULL && strlen (libhal_volume_get_fstype (volume)) > 0) {
88018c2aff7Sartem 		mount_do_fstype = (char *) map_fstype (libhal_volume_get_fstype (volume));
88118c2aff7Sartem 	}
88218c2aff7Sartem 	args[na++] = MOUNT_TYPE_OPT;
88318c2aff7Sartem 	args[na++] = mount_do_fstype;
88418c2aff7Sartem 
88518c2aff7Sartem 	args[na++] = "-o";
88618c2aff7Sartem 	mount_option_str = g_string_new (MOUNT_OPTIONS);
88718c2aff7Sartem 	for (i = 0; given_options[i] != NULL; i++) {
88818c2aff7Sartem 		g_string_append (mount_option_str, ",");
88918c2aff7Sartem 		g_string_append (mount_option_str, given_options[i]);
89018c2aff7Sartem 	}
89118c2aff7Sartem #ifdef sun
89218c2aff7Sartem 	if (append_ro) {
89318c2aff7Sartem 		g_string_append (mount_option_str, ",ro");
89418c2aff7Sartem 	}
89518c2aff7Sartem #endif
89618c2aff7Sartem 	mount_option_commasep = g_string_free (mount_option_str, FALSE); /* leak! */
89718c2aff7Sartem 	args[na++] = mount_option_commasep;
89818c2aff7Sartem 	args[na++] = (char *) device;
89918c2aff7Sartem 	args[na++] = mount_dir;
90018c2aff7Sartem 	args[na++] = NULL;
90118c2aff7Sartem 
90218c2aff7Sartem 	/* TODO FIXME XXX HACK: OK, so we should rewrite the options in /media/.hal-mtab ..
90318c2aff7Sartem 	 *                      but it doesn't really matter much at this point */
90418c2aff7Sartem 	if (!is_remount) {
90518c2aff7Sartem 		FILE *hal_mtab;
90618c2aff7Sartem 		char *mount_dir_escaped;
90718c2aff7Sartem 		FILE *hal_mtab_orig;
90818c2aff7Sartem 		int hal_mtab_orig_len;
90918c2aff7Sartem 		int num_read;
91018c2aff7Sartem 		char *hal_mtab_buf;
91118c2aff7Sartem 		char *hal_mtab_buf_old;
91218c2aff7Sartem 
91318c2aff7Sartem 		/* Maintain a list in /media/.hal-mtab with entries of the following format
91418c2aff7Sartem 		 *
91518c2aff7Sartem 		 *  <device_file>\t<uid>\t<session-id>\t<fstype>\t<options_sep_by_comma>\t<mount point>\n
91618c2aff7Sartem 		 *
91718c2aff7Sartem 		 * where session-id currently is unused and thus set to 0.
91818c2aff7Sartem 		 *
91918c2aff7Sartem 		 * Example:
92018c2aff7Sartem 		 *
92118c2aff7Sartem 		 *  /dev/sda2	500	0	hfsplus	noexec,nosuid,nodev	/media/Macintosh HD
92218c2aff7Sartem 		 *  /dev/sda4	500	0	ntfs	noexec,nosuid,nodev,umask=222	/media/Windows
92318c2aff7Sartem 		 *  /dev/sdb1	500	0	vfat	noexec,nosuid,nodev,shortname=winnt,uid=500	/media/davidz
92418c2aff7Sartem 		 */
92518c2aff7Sartem 
92618c2aff7Sartem 
92718c2aff7Sartem 		if (g_file_test ("/media/.hal-mtab", G_FILE_TEST_EXISTS)) {
92818c2aff7Sartem 			hal_mtab_orig = fopen ("/media/.hal-mtab", "r");
92918c2aff7Sartem 			if (hal_mtab_orig == NULL) {
93018c2aff7Sartem 				unknown_error ("Cannot open /media/.hal-mtab");
93118c2aff7Sartem 			}
93218c2aff7Sartem 			if (fseek (hal_mtab_orig, 0L, SEEK_END) != 0) {
93318c2aff7Sartem 				unknown_error ("Cannot seek to end of /media/.hal-mtab");
93418c2aff7Sartem 			}
93518c2aff7Sartem 			hal_mtab_orig_len = ftell (hal_mtab_orig);
93618c2aff7Sartem 			if (hal_mtab_orig_len < 0) {
93718c2aff7Sartem 				unknown_error ("Cannot determine size of /media/.hal-mtab");
93818c2aff7Sartem 			}
93918c2aff7Sartem 			rewind (hal_mtab_orig);
94018c2aff7Sartem 			hal_mtab_buf = g_new0 (char, hal_mtab_orig_len + 1);
94118c2aff7Sartem 			num_read = fread (hal_mtab_buf, 1, hal_mtab_orig_len, hal_mtab_orig);
94218c2aff7Sartem 			if (num_read != hal_mtab_orig_len) {
94318c2aff7Sartem 				unknown_error ("Cannot read from /media/.hal-mtab");
94418c2aff7Sartem 			}
94518c2aff7Sartem 			fclose (hal_mtab_orig);
94618c2aff7Sartem 		} else {
94718c2aff7Sartem 			hal_mtab_buf = g_strdup ("");
94818c2aff7Sartem 		}
94918c2aff7Sartem 
95018c2aff7Sartem 		mount_dir_escaped = g_strescape (mount_dir, NULL);
95118c2aff7Sartem #ifdef DEBUG
95218c2aff7Sartem 		printf ("%d: XYA creating /media/.hal-mtab~\n", getpid ());
95318c2aff7Sartem #endif
95418c2aff7Sartem 		hal_mtab = fopen ("/media/.hal-mtab~", "w");
95518c2aff7Sartem 		if (hal_mtab == NULL) {
95618c2aff7Sartem 			unknown_error ("Cannot create /media/.hal-mtab~");
95718c2aff7Sartem 		}
95818c2aff7Sartem 		hal_mtab_buf_old = hal_mtab_buf;
95918c2aff7Sartem 		hal_mtab_buf = g_strdup_printf ("%s%s\t%s\t0\t%s\t%s\t%s\n",
96018c2aff7Sartem 						hal_mtab_buf_old,
96118c2aff7Sartem 						device, invoked_by_uid, mount_do_fstype,
96218c2aff7Sartem 						mount_option_commasep, mount_dir_escaped);
96318c2aff7Sartem 		g_free (hal_mtab_buf_old);
96418c2aff7Sartem 		if (hal_mtab_buf_old == NULL) {
96518c2aff7Sartem 			unknown_error ("Out of memory appending to /media/.hal-mtab~");
96618c2aff7Sartem 		}
96718c2aff7Sartem 		if (fwrite (hal_mtab_buf, 1, strlen (hal_mtab_buf), hal_mtab) != strlen (hal_mtab_buf)) {
96818c2aff7Sartem 			unknown_error ("Cannot write to /media/.hal-mtab~");
96918c2aff7Sartem 		}
97018c2aff7Sartem 		fclose (hal_mtab);
97118c2aff7Sartem 		g_free (hal_mtab_buf);
97218c2aff7Sartem 		g_free (mount_dir_escaped);
97318c2aff7Sartem #ifdef DEBUG
97418c2aff7Sartem 		printf ("%d: XYA closing /media/.hal-mtab~\n", getpid ());
97518c2aff7Sartem #endif
97618c2aff7Sartem 	} /* !is_remount */
97718c2aff7Sartem 
97818c2aff7Sartem 	/* now try to mount */
97918c2aff7Sartem 	if (!g_spawn_sync ("/",
98018c2aff7Sartem 			   args,
98118c2aff7Sartem 			   NULL,
98218c2aff7Sartem 			   0,
98318c2aff7Sartem 			   NULL,
98418c2aff7Sartem 			   NULL,
98518c2aff7Sartem 			   &sout,
98618c2aff7Sartem 			   &serr,
98718c2aff7Sartem 			   &exit_status,
98818c2aff7Sartem 			   &err)) {
98918c2aff7Sartem 		printf ("Cannot execute %s\n", MOUNT);
99018c2aff7Sartem 		g_rmdir (mount_dir);
99118c2aff7Sartem 		unlink ("/media/.hal-mtab~");
99218c2aff7Sartem 		unknown_error ("Cannot spawn " MOUNT);
99318c2aff7Sartem 	}
99418c2aff7Sartem 
99518c2aff7Sartem 
99618c2aff7Sartem 	if (exit_status != 0) {
99718c2aff7Sartem 		char errstr[]  = "mount: unknown filesystem type";
99818c2aff7Sartem 
99918c2aff7Sartem 		printf ("%s error %d, stdout='%s', stderr='%s'\n", MOUNT, exit_status, sout, serr);
100018c2aff7Sartem 
100118c2aff7Sartem 		if (!is_remount) {
100218c2aff7Sartem 			g_rmdir (mount_dir);
100318c2aff7Sartem 			unlink ("/media/.hal-mtab~");
100418c2aff7Sartem 		}
100518c2aff7Sartem 
100618c2aff7Sartem 		if (strncmp (errstr, serr, sizeof (errstr) - 1) == 0) {
100718c2aff7Sartem 			unknown_filesystem (strlen (mount_fstype) > 0 ?
100818c2aff7Sartem 					    mount_fstype :
100918c2aff7Sartem 					    (volume != NULL ? libhal_volume_get_fstype (volume) : "") );
101018c2aff7Sartem 		} else {
101118c2aff7Sartem 			int n;
101218c2aff7Sartem 			for (n = 0; serr[n] != '\0'; n++) {
101318c2aff7Sartem 				if (serr[n] == '\n') {
101418c2aff7Sartem 					serr[n] = ' ';
101518c2aff7Sartem 				}
101618c2aff7Sartem 			}
101718c2aff7Sartem 			unknown_error (serr);
101818c2aff7Sartem 		}
101918c2aff7Sartem 	}
102018c2aff7Sartem 
102118c2aff7Sartem 	if (!is_remount) {
102218c2aff7Sartem 		if (rename ("/media/.hal-mtab~", "/media/.hal-mtab") != 0) {
102318c2aff7Sartem 			printf ("rename(2) failed, errno=%d -> '%s'\n", errno, strerror (errno));
102418c2aff7Sartem 			unlink ("/media/.hal-mtab~");
102518c2aff7Sartem #ifdef DEBUG
102618c2aff7Sartem 			printf ("%d: XYA failed renaming /media/.hal-mtab~ to /media/.hal-mtab\n", getpid ());
102718c2aff7Sartem #endif
102818c2aff7Sartem 			unknown_error ("Cannot rename /media/.hal-mtab~ to /media/.hal-mtab");
102918c2aff7Sartem 		}
103018c2aff7Sartem #ifdef DEBUG
103118c2aff7Sartem 		printf ("%d: XYA done renaming /media/.hal-mtab~ to /media/.hal-mtab\n", getpid ());
103218c2aff7Sartem #endif
103318c2aff7Sartem 	}
103418c2aff7Sartem 
103518c2aff7Sartem 	openlog ("hald", 0, LOG_DAEMON);
103618c2aff7Sartem 	if (is_remount) {
103718c2aff7Sartem 		syslog (LOG_INFO, "remounted %s at '%s' on behalf of uid %s", device, mount_dir, invoked_by_uid);
103818c2aff7Sartem 	} else {
103918c2aff7Sartem 		syslog (LOG_INFO, "mounted %s on behalf of uid %s", device, invoked_by_uid);
104018c2aff7Sartem 	}
104118c2aff7Sartem 	closelog ();
104218c2aff7Sartem 
104318c2aff7Sartem #ifdef sun
104418c2aff7Sartem 	if ((adt_data = get_audit_export_data (system_bus,
104518c2aff7Sartem 	    invoked_by_syscon_name, &adt_data_size)) != NULL) {
104618c2aff7Sartem 		audit_volume (adt_data, ADT_attach,
104718c2aff7Sartem 		    WEXITSTATUS(exit_status), auth_from_privilege(privilege),
104818c2aff7Sartem 		    mount_dir, device, mount_option_commasep);
104918c2aff7Sartem 		free (adt_data);
105018c2aff7Sartem 	}
105118c2aff7Sartem #endif
105218c2aff7Sartem 
105318c2aff7Sartem 	g_free (sout);
105418c2aff7Sartem 	g_free (serr);
105518c2aff7Sartem 	g_free (mount_dir);
105618c2aff7Sartem 	libhal_free_string_array (allowed_options);
105718c2aff7Sartem 	g_strfreev (given_options);
105818c2aff7Sartem }
105918c2aff7Sartem 
106018c2aff7Sartem 
106118c2aff7Sartem int
106218c2aff7Sartem main (int argc, char *argv[])
106318c2aff7Sartem {
106418c2aff7Sartem 	char *udi;
106518c2aff7Sartem 	char *device;
106618c2aff7Sartem 	LibHalVolume *volume;
106718c2aff7Sartem 	DBusError error;
106818c2aff7Sartem 	LibHalContext *hal_ctx = NULL;
106918c2aff7Sartem 	DBusConnection *system_bus = NULL;
107018c2aff7Sartem #ifdef HAVE_POLKIT
107118c2aff7Sartem 	LibPolKitContext *pol_ctx = NULL;
107218c2aff7Sartem #endif
107318c2aff7Sartem 	char *invoked_by_uid;
107418c2aff7Sartem 	char *invoked_by_syscon_name;
107518c2aff7Sartem 
107618c2aff7Sartem 	if (!lock_hal_mtab ()) {
107718c2aff7Sartem 		unknown_error ("Cannot obtain lock on /media/.hal-mtab");
107818c2aff7Sartem 	}
107918c2aff7Sartem 
108018c2aff7Sartem 	device = getenv ("HAL_PROP_BLOCK_DEVICE");
108118c2aff7Sartem 	if (device == NULL)
108218c2aff7Sartem 		usage ();
108318c2aff7Sartem 
108418c2aff7Sartem 	udi = getenv ("HAL_PROP_INFO_UDI");
108518c2aff7Sartem 	if (udi == NULL)
108618c2aff7Sartem 		usage ();
108718c2aff7Sartem 
108818c2aff7Sartem 	invoked_by_uid = getenv ("HAL_METHOD_INVOKED_BY_UID");
108918c2aff7Sartem 
109018c2aff7Sartem 	invoked_by_syscon_name = getenv ("HAL_METHOD_INVOKED_BY_SYSTEMBUS_CONNECTION_NAME");
109118c2aff7Sartem 
109218c2aff7Sartem 	dbus_error_init (&error);
109318c2aff7Sartem 	if ((hal_ctx = libhal_ctx_init_direct (&error)) == NULL) {
109418c2aff7Sartem 		printf ("Cannot connect to hald\n");
109518c2aff7Sartem 		LIBHAL_FREE_DBUS_ERROR (&error);
109618c2aff7Sartem 		usage ();
109718c2aff7Sartem 	}
109818c2aff7Sartem 
109918c2aff7Sartem 	dbus_error_init (&error);
110018c2aff7Sartem 	system_bus = dbus_bus_get (DBUS_BUS_SYSTEM, &error);
110118c2aff7Sartem 	if (system_bus == NULL) {
110218c2aff7Sartem 		printf ("Cannot connect to the system bus\n");
110318c2aff7Sartem 		LIBHAL_FREE_DBUS_ERROR (&error);
110418c2aff7Sartem 		usage ();
110518c2aff7Sartem 	}
110618c2aff7Sartem #ifdef HAVE_POLKIT
110718c2aff7Sartem 	pol_ctx = libpolkit_new_context (system_bus);
110818c2aff7Sartem 	if (pol_ctx == NULL) {
110918c2aff7Sartem 		printf ("Cannot get libpolkit context\n");
111018c2aff7Sartem 		unknown_error ("Cannot get libpolkit context");
111118c2aff7Sartem 	}
111218c2aff7Sartem #endif
111318c2aff7Sartem 
111418c2aff7Sartem 	volume = libhal_volume_from_udi (hal_ctx, udi);
111518c2aff7Sartem 	if (volume == NULL) {
111618c2aff7Sartem 		LibHalDrive *drive;
111718c2aff7Sartem 
111818c2aff7Sartem 		drive = libhal_drive_from_udi (hal_ctx, udi);
111918c2aff7Sartem 		if (drive == NULL) {
112018c2aff7Sartem 			usage ();
112118c2aff7Sartem 		} else {
112218c2aff7Sartem 			handle_mount (hal_ctx,
112318c2aff7Sartem #ifdef HAVE_POLKIT
112418c2aff7Sartem 				      pol_ctx,
112518c2aff7Sartem #endif
112618c2aff7Sartem 				      udi, NULL, drive, device, invoked_by_uid,
112718c2aff7Sartem 				      invoked_by_syscon_name, system_bus);
112818c2aff7Sartem 		}
112918c2aff7Sartem 
113018c2aff7Sartem 	} else {
113118c2aff7Sartem 		const char *drive_udi;
113218c2aff7Sartem 		LibHalDrive *drive;
113318c2aff7Sartem 
113418c2aff7Sartem 		drive_udi = libhal_volume_get_storage_device_udi (volume);
113518c2aff7Sartem 
113618c2aff7Sartem 		if (drive_udi == NULL)
113718c2aff7Sartem 			unknown_error ("Cannot get drive_udi from volume");
113818c2aff7Sartem 		drive = libhal_drive_from_udi (hal_ctx, drive_udi);
113918c2aff7Sartem 		if (drive == NULL)
114018c2aff7Sartem 			unknown_error ("Cannot get drive from hal");
114118c2aff7Sartem 
114218c2aff7Sartem 		handle_mount (hal_ctx,
114318c2aff7Sartem #ifdef HAVE_POLKIT
114418c2aff7Sartem 			      pol_ctx,
114518c2aff7Sartem #endif
114618c2aff7Sartem 			      udi, volume, drive, device, invoked_by_uid,
114718c2aff7Sartem 			      invoked_by_syscon_name, system_bus);
114818c2aff7Sartem 
114918c2aff7Sartem 	}
115018c2aff7Sartem 
115118c2aff7Sartem 	unlock_hal_mtab ();
115218c2aff7Sartem 
115318c2aff7Sartem 	return 0;
115418c2aff7Sartem }
1155