2.11.4 Настройка принадлежности usb-накопителей
В данной статье будет рассмотрен пример разграничения правил для разных пользователей.
Сначала необходимо создать udev-правило, содержащее разрешения на определенные usb-устройства, по выбранным пользователем параметрам.
nano /etc/udev/rules.d/80-alloweduserlist1.rules
ACTION!="add", GOTO="dont_remove_usb"
ENV{DRIVER}!="usb-storage", GOTO="dont_remove_usb"
ATTRS{vendor}=="0x8086",GOTO="dont_remove_usb"
ENV{DRIVER}=="usb-storage",RUN+="/bin/python3 /usr/local/bin/remove_usb.py $devpath"
LABEL="dont_remove_usb"
KERNEL=="sd[a-z][0-9]", SUBSYSTEMS=="usb", ACTION=="add", RUN+="/bin/systemctl start usb-mount-list1@%k.service"
KERNEL=="sd[a-z][0-9]", SUBSYSTEMS=="usb", ACTION=="remove", RUN+="/bin/systemctl stop usb-mount-list1@%k.service"
Затем необходимо создать скрипт для запрета монтирования устройств со следующим содержимым:
nano /usr/local/bin/remove_usb.py
#!/usr/bin/python3
import os
import sys
var = sys.argv[1].strip()
var2 = os.popen(f"echo {var} | sed 's/.*usb[[:digit:]]//' | sed 's/[a-z].*//'| sed 's/[0-9]-[0-9].//'").readlines()[0]
os.system(f"echo 0 > '/sys/bus/usb/devices{var2.strip()}authorized'")
Далее создайте сервис, отвечающий за запуск скрипта, проверяющего список доступных пользователей для данного udev-правила.
nano /etc/systemd/system/usb-mount-list1@.service
[Unit]
Description=Mount USB Drive on %i
[Service]
RemainAfterExit=true
Type=oneshot
ExecStart=/usr/bin/python3 /usr/local/bin/usb-mount.py add %i /etc/udevlist/userlist1.txt
ExecStop=/usr/bin/python3 /usr/local/bin/usb-mount.py remove %i /etc/udevlist/userlist1.txt
Перезапустите сервисы командой:
systemctl daemon-reload
После этого создайте скрипт проверки доступа пользователей:
nano /usr/local/bin/usb-mount.py
#!/usr/bin/python3
# Этот сценарий вызывается из системного юнита, как сценарий
обработки подключения/отключения накопителей.
import os
import sys
import re
def usage():
os.system('echo "Использование: ' + sys.argv[0] + ' {add|remove} device_name (например, sdb1)" "path_to_users_list" (например /etc/udevlist/userlist1.txt)')
sys.exit(1)
if len(sys.argv) != 4:
usage()
ACTION = sys.argv[1]
DEVBASE = sys.argv[2]
USERLISTPATH = sys.argv[3]
DEVICE = f"/dev/{DEVBASE}"
active_user = []
users = os.popen("who").readlines()
for u in users:
k = u.split()
if re.findall("\:\d", k[1]):
active_user.append(k[0])
# Проверяем, не примонтировано ли уже устройство
MOUNT_POINT = os.popen("echo $(/bin/mount | /bin/grep " + DEVICE + " | /usr/bin/awk '{ print $3 }')").readlines()
#
def do_mount():
global MOUNT_POINT
if MOUNT_POINT[0] != "\n":
os.system(f'echo "Предупреждение: {DEVICE} уже смонтировано в {MOUNT_POINT}" ')
sys.exit(1)
this_user=""
for user in active_user:
string = os.popen(f"loginctl user-status {user}").readlines()
# проверяем на активность владельца usb-носителя
for s in string:
if "State: active" in s: # проверка на наличие сессии пользователя
flag = True
this_user = user
break
file = open(USERLISTPATH, "r")
vars = file.readlines()
flag = False
UID = umask_u = rwx_g = ""
for var in vars:
if this_user in var:
temp = var.split(":")
if this_user in temp[0]:
flag = True
umask_u = temp[1].strip()
UID = os.popen(f"id -u {this_user}").readlines()[0].strip()
break
if flag:
umask = f"{rwx_u}00"
else:
sys.exit(1)
# Получаем информацию об устройстве : метка $ID_FS_LABEL, идентификатор $ID_FS_UUID, и тип файловой системы $ID_FS_TYPE
vars = os.popen(f"echo $(/sbin/blkid -o udev {DEVICE})").readlines()[0]
vars_ = vars.split(" ")
ID_FS_TYPE = ID_FS_LABEL = ""
for i in range(len(vars_)):
if "ID_FS_TYPE=" in vars_[i]:
ID_FS_TYPE = re.sub("ID_FS_TYPE=", "", vars_[i].strip())
elif "ID_FS_LABEL=" in vars_[i]:
ID_FS_LABEL = re.sub("ID_FS_LABEL=", "", vars_[i].strip())
# Создаём точку монтирования:
LABEL = ID_FS_LABEL
if LABEL == "":
LABEL = DEVBASE
elif os.popen('/bin/grep -q " /media/${LABEL} " /etc/mtab').readlines():
# Если точка монтирования уже существует, изменяем имя:
LABEL += f"-{DEVBASE}"
MOUNT_POINT = f"/media/{LABEL}"
os.system(f'echo "Точка монтирования: {MOUNT_POINT}"')
os.system(f"/bin/mkdir -p {MOUNT_POINT}")
# Глобальные опции монтирования
OPTS = "rw,relatime"
# Специфические опции монтирования:
if ID_FS_TYPE == "vfat":
OPTS += f",uid={UID},umask={umask},shortname=mixed,utf8=1,flush"
elif ID_FS_TYPE == "ntfs":
OPTS += f",uid={UID},umask=0{umask},shortname=mixed,utf8=1,flush"
os.system(f'echo "/bin/mount -o {OPTS} {DEVICE} {MOUNT_POINT}"')
status = os.WEXITSTATUS(os.system(f"/bin/mount -o {OPTS} {DEVICE} {MOUNT_POINT}"))
if status != 0:
os.system(f"echo Ошибка монтирования {DEVICE} (статус = {status})")
os.system(f"/bin/rmdir {MOUNT_POINT}")
sys.exit(1)
os.system(f'echo "**** Устройство {DEVICE} смонтировано в {MOUNT_POINT} ****"')
def do_unmount():
if MOUNT_POINT == "":
os.system('echo "Предупреждение: ${DEVICE} не смонтировано"')
else:
os.system(f"/bin/umount -l {DEVICE}")
os.system(f'echo "**** Отмонтировано {DEVICE}"')
# Удаление пустых каталогов
for fl in os.popen("ls /media/").readlines():
os.system(f'echo "/media/{fl}"')
if len(os.popen(f'/bin/grep -q " /media/{fl} " /etc/mtab').readlines())==0:
os.system(f'echo "Удаление точки монтирования /media/{fl}"')
os.system(f'/bin/rmdir /media/{fl}')
if "add" in ACTION:
do_mount()
elif "remove" in ACTION:
do_unmount()
else:
usage()
Следующим этапом формируется список разрешенных пользователей.
Допустимые значения umask:
0 - rwx - полные права;
1 - rw - чтение/запись;
3 - r - чтение.
mkdir -p /etc/udevlist nano /etc/udevlist/userlist1.txt
<имя_пользателя_1>:0
<имя_пользателя_2>:1
<имя_пользателя_3>:3
При необходимости формирования разных правил для разных пользователей следует по описанной выше схеме создать файлы:
/etc/udev/rules.d/81-userlist2.rules;
/etc/systemd/system/usb-mount-list2@.service;
/etc/udevlist/userlist2.txt.
Дата последнего изменения: 06.03.2023
Если вы нашли ошибку, пожалуйста, выделите текст и нажмите Ctrl+Enter.