Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

common users and mounting removable devices (USB pendrives)

33 views
Skip to first unread message

Marco Maggi

unread,
May 23, 2013, 2:27:27 PM5/23/13
to
Ciao,

after years of using GNU+Linux I feel a bit ashamed that I have never
implemented the "right" solution to the problem: allow common users to
mount USB pendrives and access their contents with the right
permissions. I am trying to do this now, but I am not sure to be doing
it right.

Slackware has a "plugdev" group, and the user "marco" (whose UID and
GID is 1000) is a member:

$ grep plugdev /etc/groups
plugdev:x:83:marco

my "/etc/sudoers" file has the lines:

User_Alias PLUGDEV = %plugdev
PLUGDEV localhost = NOPASSWD: /usr/bin/pendrive

where "pendrive" is the script below (it makes an ugly use of gawk, but
I have no will now); when the device is plugged, the access permissions
are:

$ ls -l /dev/sdb1
brw-rw---- 1 root plugdev 8, 17 May 23 20:33 /dev/sdb1

and my "/etc/fstab" file has the entry:

/dev/sdb1 /mnt/stick auto defaults,noauto,sync,nosuid,rw,group 0 0

With this setup, the user "marco" (which requires the password to use
"sudo") can indeed mount and unmount pendrives with:

$ pendrive mount
/usr/bin/sudo /bin/mount /mnt/stick -o uid=1000,gid=1000
/dev/sdb1 on /mnt/stick vfat (rw,nosuid,nodev,sync,uid=1000,gid=1000) [STORE N GO]

$ pendrive umount
/usr/bin/sudo /bin/umount /mnt/stick

while the user "marco-firefox", which is not in the "plugdev" group, is
asked the password.

Am I missing something?

TIA

#!/bin/bash
#
# USB pendrive control.

#page
#### global variables

declare -r script_PROGNAME=pendrive
declare -r script_VERSION=0.1d0

declare -r SUDO='/usr/bin/sudo'
declare -r MOUNT='/bin/mount'
declare -r UMOUNT='/bin/umount'
declare -r GAWK='/usr/bin/gawk'
declare -r GREP='/usr/bin/grep'

declare -r PENDRIVE_DEVICE=/dev/sdb1
declare -r PENDRIVE_MOUNT_POINT=/mnt/stick

declare -r USER_ID=$(/usr/bin/id --user)
declare -r GROUP_ID=$(/usr/bin/id --group)

#page
#### main commands dispatching

declare -a ACTION_DISPATCH_KEYS=(mount umount version version-only help)
declare -A ACTION_DISPATCH_FUNS=(
[mount]=script_action_mount
[umount]=script_action_umount
[help]=script_action_help
[version]=script_action_version
[version-only]=script_action_version_only)
declare -r ACTION_DISPATCH_KEYS ACTION_DISPATCH_FUNS

function script_action_mount () {
echo "$SUDO" "$MOUNT" "$PENDRIVE_MOUNT_POINT" -o uid="$USER_ID",gid="$GROUP_ID" >&2
"$SUDO" "$MOUNT" "$PENDRIVE_MOUNT_POINT" -o uid="$USER_ID",gid="$GROUP_ID"
show_mount_point "$PENDRIVE_MOUNT_POINT"
}
function script_action_umount () {
echo "$SUDO" "$UMOUNT" "$PENDRIVE_MOUNT_POINT" >&2
"$SUDO" "$UMOUNT" "$PENDRIVE_MOUNT_POINT"
show_mount_point "$PENDRIVE_MOUNT_POINT"
}
function script_action_help () {
printf 'usage: %s COMMAND [options]
Manage USB pendrives. Available COMMANDs:

$ pendrive mount
$ pendrive umount
$ pendrive help
$ pendrive version
$ pendrive version-only
' "$script_PROGNAME"
exit 2
}
function script_action_version () {
printf '%s %s\n' "$script_PROGNAME" "$script_VERSION"
exit 0
}
function script_action_version_only () {
printf '%s\n' "$script_VERSION"
exit 0
}

#page
#### helper functions

function show_mount_point () {
"$MOUNT" -l | "$GREP" "$1" | "$GAWK" '
BEGIN {
COLOR_NORM_GREEN="\033[32;40m"
COLOR_BOLD_GREEN="\033[32;40;1m"
COLOR_NORM_PURPLE="\033[35;40m"
COLOR_BOLD_PURPLE="\033[35;40;1m"
COLOR_NORM_YELLOW="\033[33;40m"
COLOR_BOLD_YELLOW="\033[33;40;1m"
COLOR_NORM_CYAN="\033[36;40m"
COLOR_BOLD_CYAN="\033[36;40;1m"
COLOR_RESET="\033[0m"
}
// {
device=$1
mount_point=$3
fs_type=$5
options=$6
label1=$7
label2=$8
label3=$9
printf "%s%-12s%s", \
COLOR_BOLD_YELLOW, device, COLOR_RESET
printf " on"
printf " %s%-12s%s",
COLOR_BOLD_CYAN, mount_point, COLOR_RESET
printf " %s%s%s", COLOR_NORM_GREEN, fs_type, COLOR_RESET
printf " %s", options
printf " %s%s %s %s%s", \
COLOR_BOLD_PURPLE, label1, label2, label3, COLOR_RESET
printf "\n"
}'
}

#page
#### auxiliary functions

function print_error_message () {
local MESSAGE=${1:?'missing error message argument'}
printf '%s error: %s\n\n' "$script_PROGNAME" "$MESSAGE" >&2
}
function print_error_message_and_exit () {
local MESSAGE=${1:?'missing error message argument'}
print_error_message "$MESSAGE"
exit 1
}
function printf_error_message () {
local MESSAGE=$(printf "$@")
print_error_message "$MESSAGE"
}
function printf_error_message_and_exit () {
local MESSAGE=$(printf "$@")
print_error_message_and_exit "$MESSAGE"
}

function print_warning_message () {
local MESSAGE=${1:?'missing warning message argument'}
printf '%s warning: %s\n' "$script_PROGNAME" "$MESSAGE" >&2
}
function printf_warning_message () {
local MESSAGE=$(printf "$@")
print_warning_message "$MESSAGE"
}

function print_verbose_message () {
local MESSAGE=${1:?'missing verbose message argument'}
printf '%s: %s\n' "$script_PROGNAME" "$MESSAGE" >&2
}
function printf_verbose_message () {
local MESSAGE=$(printf "$@")
print_verbose_message "$MESSAGE"
}

#page
#### script actions dispatching

function script_action () {
local ACTION_KEY=${1:?"missing ACTION_KEY argument to '$FUNCNAME'"}
local -a ACTION_KEYS=ACTION_${ACTION_KEY}_KEYS[@]
local -a ACTION_FUNS=ACTION_${ACTION_KEY}_FUNS[@]
shift 1
if test 1 -le $#
then
local COMMAND=$1 KEY FUN
shift 1
for KEY in "${!ACTION_KEYS}"
do
if test "$KEY" = "$COMMAND"
then
FUN=ACTION_${ACTION_KEY}_FUNS[$KEY]
${!FUN} "$@"
exit $?
fi
done
printf_error_message_and_exit 'invalid subcommand: %s\n' "$COMMAND"
else
print_error_message_and_exit \
'invalid number of arguments, use the "help" subcommand for details'
fi
exit 0
}

#page
#### done

script_action DISPATCH "$@"

### end of file
# Local Variables:
# mode: sh-mode
# End:
--
Marco Maggi

Henrik Carlqvist

unread,
May 24, 2013, 2:53:13 AM5/24/13
to
On Thu, 23 May 2013 20:27:27 +0200, Marco Maggi wrote:
> Slackware has a "plugdev" group, and the user "marco" (whose UID and
> GID is 1000) is a member:
>
> $ grep plugdev /etc/groups
> plugdev:x:83:marco
>
> my "/etc/sudoers" file has the lines:
>
> User_Alias PLUGDEV = %plugdev
> PLUGDEV localhost = NOPASSWD: /usr/bin/pendrive
>
> where "pendrive" is the script below (it makes an ugly use of gawk, but
> I have no will now); when the device is plugged, the access permissions
> are:

I haven't really used the plugdev group myself. On my systems I want all
users to be able to mount USB disks. This is solved with the following
lines in /etc/udev/rules.d/90-local.rules

KERNEL=="hd*[!0-9]", ATTR{removable}=="1", GROUP="plugdev", MODE="0666"
KERNEL=="hd*[0-9]", ATTRS{removable}=="1", GROUP="plugdev", MODE="0666"
KERNEL=="sd*[!0-9]", ATTR{removable}=="1", GROUP="plugdev", MODE="0666"
KERNEL=="sd*[0-9]", ATTRS{removable}=="1", GROUP="plugdev", MODE="0666"

Which gives rw access not only to the plugdev group but to everyone.

On my Slackware 13.1 systems I also needed to modify
/etc/dbus-1/system.d/hal.conf
My default context policy looks like this:
<policy context="default">
<!-- Allow anyone to invoke methods on the Introspectable interface --
>
<allow send_destination="org.freedesktop.Hal"
send_interface="org.freedesktop.DBus.Introspectable"/>
<!-- Allow anyone to invoke methods on the Properties interface -->
<allow send_destination="org.freedesktop.Hal"
send_interface="org.freedesktop.DBus.Properties" />
<!-- Allow anyone to invoke methods on the Manager interface -->
<allow send_destination="org.freedesktop.Hal"
send_interface="org.freedesktop.Hal.Manager"/>
<!-- Allow anyone to invoke methods on the Device interface -->
<allow send_destination="org.freedesktop.Hal"
send_interface="org.freedesktop.Hal.Device"/>
<!-- Allow members of 'users' group to mount/unmount volumes -->
<allow send_destination="org.freedesktop.Hal"
send_interface="org.freedesktop.Hal.Device.Storage"/>
<allow send_destination="org.freedesktop.Hal"
send_interface="org.freedesktop.Hal.Device.Storage.Removable"/>
<allow send_destination="org.freedesktop.Hal"
send_interface="org.freedesktop.Hal.Device.Volume"/>
<allow send_destination="org.freedesktop.Hal"
send_interface="org.freedesktop.Hal.Device.Volume.Crypto"/>
</policy>

The above is for Slackware 13.1, YMMV on other versions.

regards Henrik
--
The address in the header is only to prevent spam. My real address is:
hc351(at)poolhem.se Examples of addresses which go to spammers:
root@localhost postmaster@localhost

mrc...@gmail.com

unread,
May 24, 2013, 4:20:31 AM5/24/13
to
On Thursday, 23 May 2013 20:27:27 UTC+2, Marco Maggi wrote:
> declare -r SUDO='/usr/bin/sudo'

Damn it, it is wrong! The script "pendrive" must not use "sudo",
users must run:

$ sudo pendrive mount
$ sudo pendrive umount

Marco Maggi

unread,
May 24, 2013, 6:19:38 AM5/24/13
to
I have changed the "/etc/sudoers" stuff to:

User_Alias PLUGDEV = %plugdev
Cmnd_Alias PENDRIVE_MOUNT = /usr/local/bin/pendrive sudo-mount [0-9 ]*
Cmnd_Alias PENDRIVE_UMOUNT = /usr/local/bin/pendrive sudo-umount
Cmnd_Alias PENDRIVE_CMDS = PENDRIVE_MOUNT, PENDRIVE_UMOUNT
PLUGDEV ALL = NOPASSWD: PENDRIVE_CMDS

and revised the "pendrive" script below. Now it really
seems to work.

#!/bin/bash
#

#page
#### global variables

declare -r script_PROGNAME=pendrive
declare -r script_VERSION=0.1d0

declare -r SCRIPT_ARGV0="$0"

declare -r SUDO='/usr/bin/sudo'
declare -r MOUNT='/bin/mount'
declare -r UMOUNT='/bin/umount'
declare -r GAWK='/usr/bin/gawk'
declare -r GREP='/usr/bin/grep'
declare -r ID='/usr/bin/id'

declare -r PENDRIVE_MOUNT_POINT=/mnt/stick

#page
#### main commands dispatching

declare -a ACTION_DISPATCH_KEYS=(mount umount sudo-mount sudo-umount version version-only help)
declare -A ACTION_DISPATCH_FUNS=(
[mount]=script_action_mount
[umount]=script_action_umount
[sudo-mount]=script_action_sudo_mount
[sudo-umount]=script_action_sudo_umount
[help]=script_action_help
[version]=script_action_version
[version-only]=script_action_version_only)
declare -r ACTION_DISPATCH_KEYS ACTION_DISPATCH_FUNS

function script_action_mount () {
local -r USR_ID=$("$ID" --user)
local -r GRP_ID=$("$ID" --group)
echo "$SUDO" "$SCRIPT_ARGV0" sudo-mount "$USR_ID" "$GRP_ID"
"$SUDO" "$SCRIPT_ARGV0" sudo-mount "$USR_ID" "$GRP_ID"
show_mount_point "$PENDRIVE_MOUNT_POINT"
}
function script_action_umount () {
echo "$SUDO" "$SCRIPT_ARGV0" sudo-umount
"$SUDO" "$SCRIPT_ARGV0" sudo-umount
show_mount_point "$PENDRIVE_MOUNT_POINT"
}
function script_action_sudo_mount () {
local -r USR_ID=${1:?"$0: missing user ID"}
local -r GRP_ID=${2:?"$0: missing group ID"}
echo "$MOUNT" "$PENDRIVE_MOUNT_POINT" -o uid="$USR_ID",gid="$GRP_ID" >&2
"$MOUNT" "$PENDRIVE_MOUNT_POINT" -o uid="$USR_ID",gid="$GRP_ID"
}
function script_action_sudo_umount () {
echo "$UMOUNT" "$PENDRIVE_MOUNT_POINT" >&2
"$UMOUNT" "$PENDRIVE_MOUNT_POINT"
0 new messages