From c02e79769d9822486175dc29b177428d94082da8 Mon Sep 17 00:00:00 2001 From: IgnorantGuru Date: Mon, 4 Jun 2012 09:05:43 -0600 Subject: [PATCH] try u/mount as current user early; clean all mount points on unmount --- AUTHORS | 2 +- ChangeLog | 2 +- etc/udevil.conf | 21 +++---- src/udevil.c | 157 +++++++++++++++++++++++++++++++++++++++++++----- 4 files changed, 155 insertions(+), 27 deletions(-) diff --git a/AUTHORS b/AUTHORS index b78a3f2..35ab11c 100644 --- a/AUTHORS +++ b/AUTHORS @@ -2,7 +2,7 @@ IgnorantGuru http://igurublog.wordpress.com/ Source code taken from other projects: * spacefm (udev support) - * mount (secure realpath) + * util-linux (secure canonicalize) * udisks 1.0.4 (device info functions - modified) * pmount 0.99 (physical tty test function - modified) diff --git a/ChangeLog b/ChangeLog index cf8bbcb..ca599e8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,5 @@ 0.2.6+ - + try u/mount as current user early; clean all mount points on unmount 0.2.6 2012-06-03: replace realpath.c with canonicalize.c 0.2.5 2012-05-30: diff --git a/etc/udevil.conf b/etc/udevil.conf index 1c47d72..b16147a 100644 --- a/etc/udevil.conf +++ b/etc/udevil.conf @@ -39,9 +39,6 @@ log_keep_days = 10 # the specific user 'USERNAME'. For example, to allow user 'jim' to mount # only vfat filesystems, add: # allowed_types_jim = vfat -# Note: For greater control for specific users, including root, copy this -# file to /etc/udevil/udevil-user-USERNAME.conf replacing USERNAME with the -# desired username (eg /etc/udevil/udevil-user-jim.conf). # Setting allowed_types = * does NOT allow all types, as this is a security # risk, but does allow all recognized types. # allowed_types = $KNOWN_FILESYSTEMS, smbfs, nfs, ftpfs, curlftpfs, file @@ -61,7 +58,8 @@ allowed_types = $KNOWN_FILESYSTEMS # the internal fstype of the file. # For example, to allow only user 'bob' to mount nfs shares, add: # allowed_users_nfs = bob -# The root user is NOT automatically allowed to use udevil unless listed here. +# The root user is NOT automatically allowed to use udevil in some cases unless +# listed here (except for unmounting anything or mounting fstab devices). allowed_users = * @@ -78,7 +76,8 @@ allowed_users = * # use both of these lines: # allowed_groups_smbfs = network # allowed_groups_nfs = network -# The root group is NOT automatically allowed to use udevil unless listed here. +# The root user is NOT automatically allowed to use udevil in some cases unless +# listed here (except for unmounting anything or mounting fstab devices). allowed_groups = * @@ -107,9 +106,9 @@ allowed_media_dirs = /media, /run/media/$USER # allowed_devices is the first criteria for what block devices users may mount # or unmount. If a device is not listed in allowed_devices, it cannot be -# un/mounted. However, even if a device is listed, other factors may prevent -# its use. For example, access to system internal devices will be denied -# to normal users even if they are included in allowed_devices. +# un/mounted (unless in fstab). However, even if a device is listed, other +# factors may prevent its use. For example, access to system internal devices +# will be denied to normal users even if they are included in allowed_devices. # allowed_devices_FSTYPE, if present, is used to override allowed_devices when # mounting or unmounting a specific fstype (eg ext3, ntfs). For example, to # prevent all block devices containing an ext4 filesystem from being @@ -144,7 +143,7 @@ allowed_devices = /dev/* # forbidden_devices is used to prevent block devices from being un/mounted -# even if other settings would allow them. +# even if other settings would allow them (except devices in fstab). # forbidden_devices_FSTYPE, if present, is used to override # forbidden_devices when mounting or unmounting a specific fstype # (eg ext3, ntfs). For example, to prevent device /dev/sdd1 from being @@ -173,7 +172,7 @@ allowed_networks = * # forbidden_networks and forbidden_networks_FSTYPE are used to specify networks -# that are never allowed, even if other settings allow them. +# that are never allowed, even if other settings allow them (except fstab). # NO REVERSE LOOKUP IS PERFORMED, so including bad.com will only have an effect # if the user uses that hostname. IP lookup is always performed, so forbidding # an IP address will also forbid all corresponding hostnames. @@ -192,7 +191,7 @@ allowed_files = * # forbidden_files is used to specify files that are never allowed, even if -# other settings allow them. Specify a full path. +# other settings allow them (except fstab). Specify a full path. # Note: Wildcards may be used, but a wildcard will never match a /, except # for "forbidden_files = *". # NOTE: file paths are canonicalized before being tested, so forbidding diff --git a/src/udevil.c b/src/udevil.c index 3700004..d9d2680 100644 --- a/src/udevil.c +++ b/src/udevil.c @@ -61,6 +61,8 @@ #define ALLOWED_TYPES "$KNOWN_FILESYSTEMS,smbfs,nfs,ftpfs,curlftpfs,file" #define MAX_LOG_DAYS 60 // don't set this too high +static int command_clean(); + int verbose = 1; char* logfile = NULL; char* logmem = NULL; @@ -1804,6 +1806,69 @@ static int exec_program( const char* var, const char* msg, gboolean show_error, return exit_status; } +static int try_umount( const char* device_file, gboolean force, gboolean lazy ) +{ + // setup command + int status = 0; + int exit_status = 1; + gchar *argv[6] = { NULL }; + char* sstdout = NULL; + char* sstderr = NULL; + + int a = 0; + argv[a++] = g_strdup( read_config( "umount_program", NULL ) ); + if ( !argv[0] ) + return 1; + if ( verbose == 0 ) + argv[a++] = g_strdup( "-v" ); + if ( force ) + argv[a++] = g_strdup( "-f" ); + if ( lazy ) + argv[a++] = g_strdup( "-l" ); + argv[a++] = g_strdup( device_file ); + char* allarg = g_strjoinv( " ", argv ); + + // insurance + drop_privileges( 0 ); + + // log + wlog( "udevil: trying umount as current user\n", NULL, 0 ); + wlog( "USER: %s\n", allarg, 0 ); + g_free( allarg ); + + // run + if ( g_spawn_sync( NULL, argv, NULL, 0, NULL, NULL, &sstdout, &sstderr, &status, NULL ) ) + { + if ( status && WIFEXITED( status ) ) + exit_status = WEXITSTATUS( status ); + else + exit_status = 0; + } + else + wlog( "udevil: warning: unable to run umount (%s)\n", + read_config( "umount_program", NULL ), 1 ); + + if ( exit_status ) + { + char* str = g_strdup_printf( " umount exit status = %d\n", exit_status ); + wlog( str, NULL, 0 ); + g_free( str ); + g_free( sstdout ); + g_free( sstderr ); + return 1; + } + + // success - show output + wlog( "udevil: success running umount as current user\n", NULL, 1 ); + if ( sstderr ) + fprintf( stderr, sstderr ); + if ( sstdout ) + fprintf( stdout, sstdout ); + g_free( sstdout ); + g_free( sstderr ); + return 0; +} + static int umount_path( const char* path, gboolean force, gboolean lazy ) { // setup command @@ -2488,6 +2553,77 @@ _get_type: } } + // try normal user u/mount early + if ( !data->point ) + { + if ( data->cmd_type == CMD_UNMOUNT ) + { + ret = try_umount( type == MOUNT_NET ? netmount->url : data->device_file, + data->force, data->lazy ); + if ( ret == 0 ) + { + // success_exec + str = g_strdup_printf( "%s unmounted %s", g_get_user_name(), + type == MOUNT_NET ? netmount->url : data->device_file ); + exec_program( "success_rootexec", str, FALSE, TRUE ); + exec_program( "success_exec", str, FALSE, FALSE ); + g_free( str ); + if ( orig_euid == 0 ) + command_clean(); + return 0; + } + } + else if ( data->cmd_type == CMD_MOUNT + && !( data->options && strstr( data->options, "remount" ) ) ) + { + if ( mount_knows( type == MOUNT_NET ? netmount->url : data->device_file ) ) + { + // mount knows (in fstab) so mount as normal user with only specified opts + wlog( "udevil: %s is known to mount - running mount as current user\n", + type == MOUNT_NET ? netmount->url : data->device_file, 1 ); + if ( data->fstype ) + wlog( "udevil: warning: fstype ignored for device in fstab (or specify mount point)\n", + NULL, 1 ); + if ( data->options ) + wlog( "udevil: warning: options ignored for device in fstab (or specify mount point)\n", + NULL, 1 ); + + ret = mount_device( type == MOUNT_NET ? netmount->url : data->device_file, + NULL, NULL, NULL, FALSE ); + // print + if ( !ret ) + { + if ( device_is_mounted_mtab( + type == MOUNT_NET ? netmount->url : data->device_file, + &str, NULL ) ) + { + str = g_strdup_printf( "Mounted %s at %s\n", + type == MOUNT_NET ? netmount->url : data->device_file, + str ); + } + else + str = g_strdup_printf( "Mounted %s\n", + type == MOUNT_NET ? netmount->url : data->device_file ); + wlog( str, NULL, -1 ); + g_free( str ); + + // success_exec + if ( !ret ) + { + str = g_strdup_printf( "%s mounted %s (in fstab)", + g_get_user_name(), + type == MOUNT_NET ? netmount->url : data->device_file ); + exec_program( "success_rootexec", str, FALSE, TRUE ); + exec_program( "success_exec", str, FALSE, FALSE ); + g_free( str ); + } + } + return ret; + } + } + ret = 0; + } + // determine device from unmount point if ( data->cmd_type == CMD_UNMOUNT && type == MOUNT_FILE ) { @@ -2579,6 +2715,7 @@ _get_type: } // get fstype and device info + ret = 0; if ( type == MOUNT_NET ) { fstype = g_strdup( netmount->fstype ); @@ -3059,24 +3196,16 @@ _get_type: if ( data->point && !( ret = umount_path( data->point, data->force, data->lazy ) ) ) { - // remove mount point if udevil created - str = g_build_filename( data->point, ".udevil-mount-point", NULL ); - restore_privileges(); // needed for stat and rm - if ( stat64( str, &statbuf ) == 0 && statbuf.st_uid == 0 ) - { - // .udevil-mount-point exists and is root-owned - unlink ( str ); - rmdir( data->point ); - } - g_free( str ); - drop_privileges( 0 ); - // success_exec str = g_strdup_printf( "%s unmounted %s", g_get_user_name(), data->point ); exec_program( "success_rootexec", str, FALSE, TRUE ); exec_program( "success_exec", str, FALSE, FALSE ); g_free( str ); + + // cleanup mount points + if ( orig_euid == 0 ) + command_clean(); } goto _finish; } @@ -3288,8 +3417,8 @@ _get_type: if ( mount_knows( type == MOUNT_NET ? netmount->url : data->device_file ) ) { // mount knows (in fstab) so mount as normal user with only specified opts - wlog( "udevil: %s is known to mount - running mount as normal user\n", - data->device_file, 1 ); + wlog( "udevil: %s is known to mount - running mount as current user\n", + type == MOUNT_NET ? netmount->url : data->device_file, 1 ); if ( data->fstype ) wlog( "udevil: warning: fstype ignored for device in fstab (or specify mount point)\n", NULL, 1 );